猫眼电影的各种爬取方法
按理说这篇随笔上周就要写的,可用 request 一直获取不到详情页信息,这天在网上看到一个说法,说是在 requests.get 后加个 headers 就好了,试了试果然可以实现,于是重新回顾一下,正好对 pyquery 的使用方法理解的差不多了,今天用三种方法分别介绍一下猫眼电影的爬取。
一般爬猫眼电影有两种方法,一种就像我前段时间写的豆瓣电影爬取方法一样,可以只获取全部电影所在的详情页内容,然后利用 正则表达式 一个一个提取,另一种就是先获取全部电影所在的详情页内容,在分别获取每个电影对应的详情页内容,再利用 正则表达式 或 pyquery 获取。
方法一:只获取全部电影所在的详情页内容
import requests from requests.exceptions import RequestException from multiprocessing import Pool import re import json def get_one_page(url): # 获取网页的 URL try: headers = { 'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' } # 加上headers,网站认为是浏览器访问,就能爬取猫眼电影 response = requests.get(url,headers = headers) if response.status_code == 200: # 得到网页的响应 return response.text return None except RequestException: return None def parse_one_page(html): # 提取出,‘序列号’,‘电影标题’,‘上映时间’,‘评分’ pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?<a.*?title="(.*?)".*?' +'<p.*?releasetime">(.*?)</p>.*?<i.*?integer">(.*?)</i>' +'.*?fraction">(.*?)</i>.*?</dd>',re.S) items = re.findall(pattern, html) for item in items: yield{ 'index':item[0], 'title':item[1], 'releasetime':item[2].strip()[5:], # str.strip()就是把这个字符串头和尾的空格,以及位于头尾的\n \t之类给删掉 'score':item[3]+item[4] } def write_to_file(content): # 把提取出来的信息写到文件夹 with open('result.txt','a',encoding='utf8')as f: f.write(json.dumps(content,ensure_ascii=False)+'\n') f.close() def main(offset): url = 'http://maoyan.com/board/4?offset=' + str(offset) # 共提取10个网页内容 html = get_one_page(url) # 每个网页对应的信息代码 for item in parse_one_page(html): print(item) write_to_file(item) if __name__ == '__main__': pool = Pool() pool.map(main,[i*10 for i in range(10)]) # for i in range(10): # main(i*10) #for 循环比多进程运行慢,但得到的结果是顺序排列的
尤其要讲一下
items = re.findall(pattern, html)
for item in items:
yield{
'index':item[0],
'title':item[1],
'releasetime':item[2].strip()[5:], # str.strip()就是把这个字符串头和尾的空格,以及位于头尾的\n \t之类给删掉
'score':item[3]+item[4]
}
items是一个字典,里面包含了10个 list ,每个item代表一个 list ,包含一部电影的详细内容, yield 返回的内容必须是 item[0],不能是 items[0]。
方法二:先获取全部电影所在的详情页内容,在分别获取每个电影对应的详情页内容
通过观察发现,html 里 有一个 href="/films/1203",刚好对应第二层详情页的 url ,通过正则表达式提取出来,再拼接成字符串,最后经过
get_page_detail(item) 获取该页内容,最后再通过 pyquery 进行内容爬取,代码如下:
import requests from requests.exceptions import RequestException from multiprocessing import Pool from pyquery import PyQuery as pq import re import json def get_page_index(offset): try: url = 'http://maoyan.com/board/4?offset=' + str(offset) # 共提取10个网页内容 headers = { 'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' } # 加上headers,网站认为是浏览器访问,就能爬取猫眼电影 response = requests.get(url,headers = headers) if response.status_code == 200: # 得到网页的响应 return response.text return None except RequestException: return None def parse_page_index(html): # 获取页面的url pattern = re.compile('.*?<dd>.*?<a.*?="(.*?)".*?</a>.*?</dd>',re.S) items = re.findall(pattern, html) for i in range(10): yield(items[i]) def get_page_detail(item): try: url = 'http://maoyan.com' + str(item) # 共提取10个网页内容 headers = { 'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' } # 加上headers,网站认为是浏览器访问,就能爬取猫眼电影 response = requests.get(url,headers = headers) if response.status_code == 200: # 得到网页的响应 return response.text return None except RequestException: return None def parse_page_detail(html): doc = pq(html) title = doc('.movie-brief-container > h3').text() score = doc('.movie-stats-container > div:nth-child(1) > div > span > span').text() introduce = doc('.active > div:nth-child(1) > div.mod-content > span').text() return{ 'title':title, 'score':score, } def write_to_file(content): # 把提取出来的信息写到文件夹 with open('result.txt','a',encoding='utf8')as f: f.write(json.dumps(content,ensure_ascii=False)+'\n') f.close() def main(offset): html = get_page_index(offset) # 每个网页对应的信息代码 for item in parse_page_index(html): html = get_page_detail(item) if html: result = parse_page_detail(html) write_to_file(result) print(result) if __name__ == '__main__': # pool = Pool() # pool.map(main,[i*10 for i in range(10)]) for i in range(10): main(i*10) # for循环比多进程运行慢,但得到的结果是顺序排列的
得分 score 得到的结果不是,应该是编码转换问题,有待进一步解决。