1 目标站点的分析
2 流程框架
- 抓取单页内容
利用requests请求目标站点,得到单个网页HTML代码,返回结果。
- 正则表达式分析
根据HTML代码分析得到电影的名称、主演、上映、时间、评分、图片链接等信息。
- 保存至文件
通过文件的形式将结果保存,每一部电影一个结果一行Json字符串。
- 开启多循环及多线程
对多页内容遍历,开启多线程提高抓取速度。
3 爬虫实战
3.1 导入头文件
"""This module is 爬取猫眼top100"""
import json # 保存文件时用到json格式
import re # 正则表达式
from multiprocessing import Pool # 最后使用了多线程,极大提高速度
import requests
from requests.exceptions import RequestException # 引入异常类
3.2 定义获取单页内容函数
def get_one_page(url):
'''获取单页内容'''
try:
# 不加headers会被猫眼禁止访问
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
'(KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'}
response = requests.get(url, headers=headers)
# 若状态码等于200代表成功,返回网页结果
if response.status_code == 200:
return response.text
return None
except RequestException: # 否则返回空值
return None
3.3 定义解析单个网页函数
def parse_one_page(html):
'''解析单个网页'''
# 声明正则表达式对象
pattern = re.compile(r'<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?class="name"><a'
'.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
'.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html) # 查找所有符合的元素
for item in items:
yield { # 建立一个字典生成器item,美化输出
'index': item[0],
'image': item[1],
'title': item[2],
'actor': item[3].strip()[3:], # 删除字符串首位空格
'time': item[4].strip()[5:],
'score': item[5]+item[6]
}
3.4 定义保存文件函数
def write_to_file(content):
'''save file'''
# 'a'表示往后追加的方式添加内容。
# encoding和ensure_ascii参数确保显示中文
# json.dumps()用于将dict类型的数据转成str,因为如果直接将dict类型的数据写入json文件中会发生报错
with open('Maoyantop100/result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False)+'\n')
3.5 定义主函数
def main(offset):
'''main'''
# 共十页,offset=[0,10,20,30,40,...,90]
url = 'http://maoyan.com/board/4?offset=' + str(offset)
# 用变量html来结果返回结果
html = get_one_page(url)
# parse_one_page返回items
for item in parse_one_page(html):
print(item) # item是一个字典生成器
write_to_file(item) # 把每个字典打印出来并保存
3.6 __name__
if __name__ == '__main__':
# for i in range(10): # 单线程方法
# main(i*10)
# 多线程方法
pool = Pool() # 声明一个进程池
pool.map(main, [i*10 for i in range(10)]) # 利用map函数
pool.close() # 停止进入新进程
pool.join() # 等待子进程完成