- '''Requests + 正则表达式爬取猫眼电影 TOP100'''
- '''
- 流程框架:
- 抓去单页内容: 利用 requests 请求目标站点, 得到单个网页 html 代码, 返回结果.
- 正则表达式分析: 根据 HTML 代码分析得到电影的名称, 主演, 上映时间, 评分, 图片链接等信息.
- 保存至文件: 通过文件的形式保存结果, 每一部电影一个结果一行 Json 字符串.
- 开启循环及多线程: 对多页内容遍历, 开启多线程提高抓取速度.
- '''
- import requests
- import re
- from requests.exceptions import RequestException
- import JSON
- from multiprocessing import Pool
- def get_one_page(url,headers):
- '''得到网页源码'''
- try:
- #此处必须要传入 headers 参数, 否则因为有些网站服务器的反爬机制, 会返回 403 Forbidden. 参考: https://blog.csdn.net/lv0817/article/details/79185322
- response = requests.get(url=url,headers=headers) #这里要注意, 必须使用 url=url,headers=headers 的格式, 否则传参无效.
- if response.status_code == 200:
- return response.text
- return None
- #可以查看 requests 库的官方文档的 Exceptions 模块, 可知 RequestException 为所有异常的父类或间接父类.
- except RequestException:
- return None
- def parse_one_page(HTML):
- '''解析得到的网页源码'''
- #编译正则表达式
- pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>'
- '.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
- items = re.findall(pattern,HTML)
- #创建一个生成器
- for item in items:
- yield {
- 'index':item[0],
- 'image':item[1],
- 'title':item[2],
- 'actor':item[3].strip()[3:],
- 'time':item[4][5:],
- 'score':item[5]+item[6]
- }
- def write_to_file(content):
- '''解析好的数据写入到文件'''
- with open('result.txt','a',encoding='utf-8') as f: #'a'表示内容可追加. 当有中文时, 指定编码 utf-8 防止乱码.
- #JSON.dumps 序列化时对中文默认使用的 ascii 编码. 想输出真正的中文需要指定 ensure_ascii = False.
- f.write(JSON.dumps(content,ensure_ascii=False) + '\n') #JSON.dumps 将字典转换为字符串
- f.close()
- def main(offset):
- url = "http://maoyan.com/board/4?offset=" + str(offset) #点击下一页观察网址可知
- headers = {
- 'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)ApplewebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
- }
- HTML = get_one_page(url,headers)
- #遍历生成器
- for item in parse_one_page(HTML):
- print(item)
- write_to_file(item)
- if __name__ == '__main__':
- # for i in range(10):
- # main(i*10)
- #如果要实现秒抓的话, 就要使用多进程.
- #进程池提供指定数量的进程供用户调用, 如果有新的请求提交到进程池, 池子还没有满, 它就会创建新的进程来执行请求, 如果池子满了就先等待.
- #构造进程池
- pool = Pool() #声明一个进程池
- pool.map(main,[i*10 for i in range(10)]) #第一个参数是方法名, 第二个参数是可遍历对象. map 方法作用是, 拿出可遍历数组中的每一个值当做函数的参数, 然后创建一个个的进程, 放到进程池里面去运行.
来源: http://www.bubuko.com/infodetail-2865255.html