失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > python3网络爬虫开发实战-抓取猫眼电影排行(正则表达式版)

python3网络爬虫开发实战-抓取猫眼电影排行(正则表达式版)

时间:2021-06-27 07:38:51

相关推荐

python3网络爬虫开发实战-抓取猫眼电影排行(正则表达式版)

抓取猫眼电影排行

目前没有学习HTML解析库,这里先选用正则表达式作为解析工具

目标

提取出猫眼电影top100的电影名称、时间、评分、图片等信息。提取的站点URL为/board/4,提取的结果以文件形式保存下来。

抓取分析

首页显示的是top10,点击下面的 [第二页],URL变成了 /board/4?offset=10,这时显示的是排行11-20名的电影。当我们分开请求10次,offset参数分别设置为0、10、20…90,获取不同页面之后,再用正则表达式提取出相关信息,就可以得到top100 的所有电影信息。

抓取首页

估计是由于学习此书的人比较多,猫眼对反爬的策略有所增强。header中如果只有User-Agent ,有时会被限制,跳转的猫眼验证页面。因此,还需要增加Cookie。

import requestsdef get_one_page(url):headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Cookie':'__mta=244153658.1609735789043.1609814345631.1609903887876.9; uuid_n_v=v1; uuid=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _lxsdk_cuid=176cbbad8c4c8-0687fad5143e0b-3e604000-144000-176cbbad8c4c8; _lxsdk=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _csrf=e80757462cd1516a77cd1805be934c54f7d4e90601451188280cb41fd6c4871a; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1609735788,1609764730,1609812449,1609903888; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1609903888; _lxsdk_s=176d5bfd5c7-e23-d69-9d%7C%7C2'}result = requests.get(url, headers=headers)if result.status_code==200:return result.textreturn Nonedef main():url = '/board/4'html = get_one_page(url)print(html)main()

正则提取

在Network 监听组件中查看源代码

可以看到一部电影信息对应的是一个dd节点,我们用正则表达式来提取里面的电影信息(排名、电影图片链接、电影名称、主演、电影发布时间、评分)。

首先是排名:

<dd>.*?board-index.*?>(.*?)</i>

这时候代码:

import requestsimport redef get_one_page(url):headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Cookie':'__mta=244153658.1609735789043.1609814345631.1609903887876.9; uuid_n_v=v1; uuid=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _lxsdk_cuid=176cbbad8c4c8-0687fad5143e0b-3e604000-144000-176cbbad8c4c8; _lxsdk=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _csrf=e80757462cd1516a77cd1805be934c54f7d4e90601451188280cb41fd6c4871a; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1609735788,1609764730,1609812449,1609903888; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1609903888; _lxsdk_s=176d5bfd5c7-e23-d69-9d%7C%7C2'}result = requests.get(url, headers=headers)if result.status_code==200:return result.textreturn Nonedef parse_one_page(html):pattern = pile('<dd>.*?board-index.*?>(.*?)</i>', re.S)items = re.findall(pattern,html)return itemsdef main():url = '/board/4'html = get_one_page(url)print(parse_one_page(html))main()

运行结果:

['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

然后看电影图片链接,可以看到后面有个a节点,内部有两个img节点。第二个img节点的data-src 属性是图片链接。正则表达式改写如下:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)"

这时运行结果:

然后看电影名。后面p节点内,class 为name。可以用name作为标志位,提取a节点的整文内容。正则表达式改写如下:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><.*?>(.*?)</a>

运行结果

提取主演、发布时间、评分也是一样的道理。最后的正则表达式为:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>

这时程序的运行结果:

通过前面正则表达式那一节的学习我们可以知道,re.findall() 得到的是一个由元组组成的列表。当然,从上面的这个结果也可以看出来。此外我们发现数据比较乱(存在空格和换行),我们将匹配结果处理一下,遍历提取结果并生成字典。整体代码如下:

import requestsimport redef get_one_page(url):headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Cookie':'__mta=244153658.1609735789043.1609814345631.1609903887876.9; uuid_n_v=v1; uuid=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _lxsdk_cuid=176cbbad8c4c8-0687fad5143e0b-3e604000-144000-176cbbad8c4c8; _lxsdk=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _csrf=e80757462cd1516a77cd1805be934c54f7d4e90601451188280cb41fd6c4871a; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1609735788,1609764730,1609812449,1609903888; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1609903888; _lxsdk_s=176d5bfd5c7-e23-d69-9d%7C%7C2'}result = requests.get(url, headers=headers)if result.status_code==200:return result.textreturn Nonedef parse_one_page(html):pattern = pile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>', re.S)items = re.findall(pattern,html)for item in items:yield {'index': item[0],'image': item[1],'title': item[2].strip(),'actor': item[3].strip()[3:],'time': item[4].strip()[5:],'score': item[5].strip() +item[6].strip()}def main():url = '/board/4'html = get_one_page(url)for x in parse_one_page(html):print(x)main()

程序运行结果:

关于yield,在前一篇博文中有写:传送门

到此,我们就成功提取了单页的电影信息。

写入文件

我们将我们将提取的结果写入文本文件。通过JSON库的dumps() 方法实现字典的序列号,并指定ensure_ascii 参数为 False,这样可以保证输出结果是中文形式而不是Unicode编码。代码如下:

def write_to_file(content):with open('result.txt', 'a', encoding='utf-8') as f_obj:f_obj.write(json.dumps(content, ensure_ascii=False +'\n'))

此处的content 参数是一部电影的提取结果,是一个字典。

此时整体代码为:

import requestsimport reimport jsondef get_one_page(url):headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Cookie':'__mta=244153658.1609735789043.1609814345631.1609903887876.9; uuid_n_v=v1; uuid=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _lxsdk_cuid=176cbbad8c4c8-0687fad5143e0b-3e604000-144000-176cbbad8c4c8; _lxsdk=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _csrf=e80757462cd1516a77cd1805be934c54f7d4e90601451188280cb41fd6c4871a; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1609735788,1609764730,1609812449,1609903888; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1609903888; _lxsdk_s=176d5bfd5c7-e23-d69-9d%7C%7C2'}result = requests.get(url, headers=headers)if result.status_code==200:return result.textreturn Nonedef parse_one_page(html):pattern = pile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>', re.S)items = re.findall(pattern,html)for item in items:yield {'index': item[0],'image': item[1],'title': item[2].strip(),'actor': item[3].strip()[3:],'time': item[4].strip()[5:],'score': item[5].strip() +item[6].strip()}def write_to_file(content):with open('result.txt', 'a', encoding='utf-8') as f_obj:f_obj.write(json.dumps(content, ensure_ascii=False)+'\n')def main():url = '/board/4'html = get_one_page(url)for x in parse_one_page(html):write_to_file(x)main()

程序运行之后,成功输出了result.txt 文件

分页爬取

因为我们需要爬取的是猫眼电影的top100,所以还需要遍历,给链接传入offset 参数,此时添加如下调用:

if __name__=='__main__':for i in range(10):main(offset=i*10)

对main() 方法进行修改,接受一个offset 值作为偏移量,然后构造URL进行爬取。代码如下:

def main(offset):url = '/board/4?offset='+str(offset)html = get_one_page(url)for x in parse_one_page(html):write_to_file(x)

完整代码:

import requestsimport reimport jsonimport timefrom requests.exceptions import RequestExceptiondef get_one_page(url):try:headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Cookie':'__mta=244153658.1609735789043.1609814345631.1609903887876.9; uuid_n_v=v1; uuid=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _lxsdk_cuid=176cbbad8c4c8-0687fad5143e0b-3e604000-144000-176cbbad8c4c8; _lxsdk=44FD87D04E4811EBB586F7EF3F3BEBB881E6A67E34BF46848671B5C44D132AF8; _csrf=e80757462cd1516a77cd1805be934c54f7d4e90601451188280cb41fd6c4871a; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1609735788,1609764730,1609812449,1609903888; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1609903888; _lxsdk_s=176d5bfd5c7-e23-d69-9d%7C%7C2'}result = requests.get(url, headers=headers)if result.status_code==200:return result.textreturn Noneexcept RequestException:return Nonedef parse_one_page(html):pattern = pile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>', re.S)items = re.findall(pattern,html)for item in items:yield {'index': item[0],'image': item[1],'title': item[2].strip(),'actor': item[3].strip()[3:],'time': item[4].strip()[5:],'score': item[5].strip() +item[6].strip()}def write_to_file(content):with open('result.txt', 'a', encoding='utf-8') as f_obj:f_obj.write(json.dumps(content, ensure_ascii=False)+'\n')def main(offset):url = '/board/4?offset=' + str(offset)html = get_one_page(url)for x in parse_one_page(html):write_to_file(x)if __name__=='__main__':for i in range(10):main(offset=i*10)time.sleep(1)

现在猫眼多了反爬虫,如果速度过快,则会无响应。所以后面加了一个延时等待。

输出结果:

如果觉得《python3网络爬虫开发实战-抓取猫眼电影排行(正则表达式版)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。