概述
Reqeusts + PyQuery + PyMongo实战
- 一、准备工作
- 二、爬取目标
- 三、爬取代码及注释
一、准备工作
- 实现环境-Python3
- 程序加速-多进程
- 网页请求-requests库
- 内容匹配-re库
- 网页解析-pyquery库
- 数据存储-MongoDB
二、爬取目标
爬取页面:https://static1.scrape.cuiqingcai.com/
- 使用requests库爬取站点每一页的电影列表,顺着列表爬取每个电影的详情页。
- 用 pyquery 和正则表达式提取每部电影的名称、封面、类别、上映时间、评分、剧情简介等内容。
- 把以上爬取的内容存入 MongoDB 数据库。
- 使用多进程实现爬取的加速。
三、爬取代码及注释
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import requests
# 爬取页面
import logging
# 输出信息
import re
# 实现正则表达式
import pymongo
# 存储数据
from pyquery import PyQuery as pq
# 解析页面
from urllib.parse import urljoin
# URL拼接
import multiprocessing # 多进程
# 定义日志输出级别和格式
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
# 当前站点根URL
BASE_URL = 'https://static1.scrape.cuiqingcai.com'
# 当前站点的页数
TOTAL_PAGE = 10
# 定义MongoDB基本连接信息,如host,port,还可以定义应户名和密码等
MONGO_CONNECTION_STRING = 'mongodb://localhost:27017'
# 数据库名称
MONGO_DB_NAME = 'movies'
# 集合名称
MONGO_COLLECTION_NAME = 'movies'
# 连接客户端
client = pymongo.MongoClient(MONGO_CONNECTION_STRING)
# 创建数据库
db = client['movies']
# 创建文档
collection = db['movies']
# 存储数据到数据库
def save_data(data):
# 第 1 个参数是查询条件,即根据 name 进行查询;第 2 个参数是 data 对象本身,也就是所有的数据
# 第 3 个参数很关键,这里实际上是 upsert 参数,如果把这个设置为 True,则可以做到存在即更新,不存在即插入的功能
collection.update_one({
'name': data.get('name')
}, {
'$set': data
}, upsert=True)
# 接受一个url,返回一个HTML页面代码
def scrape_page(url):
logging.info('scraping %s...', url)
try:
response = requests.get(url)
# 响应状态码正常,则返回HTML页面代码
if response.status_code == 200:
return response.text
# 不正常,输出错误日志信息
logging.error('get invalid status code %s while scraping %s', response.status_code, url)
except requests.RequestException:
# 将 logging 的 error 方法的 exc_info 参数设置为 True 则可以打印出 Traceback 错误堆栈信息
logging.error('error occurred while scraping %s', url, exc_info=True)
# 同上,但是函数名说明含义
def scrape_detail(url):
return scrape_page(url)
# 解析每个页面的内容
def parse_detail(html):
doc = pq(html)
# CSS选择器和正则,根据页面分析可知
cover = doc('img.cover').attr('src')
name = doc('a>h2').text()
categories = [item.text() for item in doc('.categories button span').items()]
published_at = doc('.info:contains(上映)').text()
published_at = re.search('(d{4}-d{2}-d{2})', published_at).group(1)
if published_at and re.search('(d{4}-d{2}-d{2})', published_at) else None
drama = doc('.drama p').text()
score = doc('p.score').text()
score = float(score) if score else None
return {
'cover': cover,
'name': name,
'categories': categories,
'published_at': published_at,
'drama': drama,
'score': score
}
# 拼接页数与根URL,得到每页的完整URL
def scrape_index(page):
index_url = f'{BASE_URL}/page/{page}'
return scrape_page(index_url)
# 解析出每页的站点主页,每部电影页面的连接
def parse_index(html):
doc = pq(html)
# 电影页面的不完整连接,根据页面分析得知
links = doc(".el-card .name")
for link in links.items():
# 每个电影的 不完整链接
href = link.attr('href')
# 根URL 与 不完整链接 拼接成完整连接
detail_url = urljoin(BASE_URL, href)
logging.info('get detail url %s', detail_url)
# yield 生成器相比 return一次返回所有结果的优势,反应更迅速,更节省空间,使用更灵活
yield detail_url
# 主函数
def main(page):
# 该页的主页面的HTML
index_html = scrape_index(page)
# 该HTML中所有图片的URL
detail_urls = parse_index(index_html)
# 遍历每一个URL
for detail_url in detail_urls:
# 获取该URL的HTML
detail_html = scrape_detail(detail_url)
# 解析该HTML的数据内容
data = parse_detail(detail_html)
# 每解析一个电影测打印出该电影的内容
logging.info('details urls %s', data)
# 数据库相关日志和函数
logging.info('saving data to mongodb')
save_data(data)
logging.info('data saved successfully')
if __name__ == '__main__':
# 进程池
pool = multiprocessing.Pool()
# 每一页都开一个进程
pages = range(1, TOTAL_PAGE+1)
# 每个pages值对应一个main函数,开启一个进程
pool.map(main, pages)
# 关闭进程池
pool.close()
# 主进程等待子进程结束才结束
pool.join()
# 21:57:41,838-21:58:25,891
44s
- 单进程
# 22:00:11,633-22:00:26,956
13s
- 多进程
最后
以上就是光亮星月为你收集整理的爬虫实战(一) 简单静态网页爬取及数据存储一、准备工作二、爬取目标三、爬取代码及注释的全部内容,希望文章能够帮你解决爬虫实战(一) 简单静态网页爬取及数据存储一、准备工作二、爬取目标三、爬取代码及注释所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复