投稿    登录
欢迎来访~

[Python3网络爬虫开发实战] 3.4-抓取猫眼电影排行

Python 崔庆才 49311浏览 10评论

扫码或搜索:进击的Coder

发送

即可立即永久解锁本站全部文章

本节中,我们利用requests库和正则表达式来抓取猫眼电影TOP100的相关内容。requests比urllib使用更加方便,而且目前我们还没有系统学习HTML解析库,所以这里就选用正则表达式来作为解析工具。

1. 本节目标

本节中,我们要提取出猫眼电影TOP100的电影名称、时间、评分、图片等信息,提取的站点URL为http://maoyan.com/board/4,提取的结果会以文件形式保存下来。

2. 准备工作

在本节开始之前,请确保已经正确安装好了requests库。如果没有安装,可以参考第1章的安装说明。

3. 抓取分析

我们需要抓取的目标站点为http://maoyan.com/board/4,打开之后便可以查看到榜单信息,如图3-11所示。 图3-11 榜单信息

排名第一的电影是霸王别姬,页面中显示的有效信息有影片名称、主演、上映时间、上映地区、评分、图片等信息。

将网页滚动到最下方,可以发现有分页的列表,直接点击第2页,观察页面的URL和内容发生了怎样的变化,如图3-12所示。

图3-12 页面URL变化

可以发现页面的URL变成http://maoyan.com/board/4?offset=10,比之前的URL多了一个参数,那就是offset=10,而目前显示的结果是排行11~20名的电影,初步推断这是一个偏移量的参数。再点击下一页,发现页面的URL变成了http://maoyan.com/board/4?offset=20,参数offset变成了20,而显示的结果是排行21~30的电影。

由此可以总结出规律,offset代表偏移量值,如果偏移量为n,则显示的电影序号就是n+1n+10,每页显示10个。所以,如果想获取TOP100电影,只需要分开请求10次,而10次的offset参数分别设置为0、10、20、…90即可,这样获取不同的页面之后,再用正则表达式提取出相关信息,就可以得到TOP100的所有电影信息了。

4. 抓取首页

接下来用代码实现这个过程。首先抓取第一页的内容。我们实现了get_one_page()方法,并给它传入url参数。然后将抓取的页面结果返回,再通过main()方法调用。初步代码实现如下:

这样运行之后,就可以成功获取首页的源代码了。获取源代码后,就需要解析页面,提取出我们想要的信息。

5. 正则提取

接下来,回到网页看一下页面的真实源码。在开发者模式下的Network监听组件中查看源代码,如图3-13所示。

图3-13 源代码

注意,这里不要在Elements选项卡中直接查看源码,因为那里的源码可能经过JavaScript操作而与原始请求不同,而是需要从Network选项卡部分查看原始请求得到的源码。

查看其中一个条目的源代码,如图3-14所示。

图3-14 源代码

可以看到,一部电影信息对应的源代码是一个dd节点,我们用正则表达式来提取这里面的一些电影信息。首先,需要提取它的排名信息。而它的排名信息是在classboard-indexi节点内,这里利用非贪婪匹配来提取i节点内的信息,正则表达式写为:

随后需要提取电影的图片。可以看到,后面有a节点,其内部有两个img节点。经过检查后发现,第二个img节点的data-src属性是图片的链接。这里提取第二个img节点的data-src属性,正则表达式可以改写如下:

再往后,需要提取电影的名称,它在后面的p节点内,classname。所以,可以用name做一个标志位,然后进一步提取到其内a节点的正文内容,此时正则表达式改写如下:

再提取主演、发布时间、评分等内容时,都是同样的原理。最后,正则表达式写为:

这样一个正则表达式可以匹配一个电影的结果,里面匹配了7个信息。接下来,通过调用findall()方法提取出所有的内容。

接下来,我们再定义解析页面的方法parse_one_page(),主要是通过正则表达式来从结果中提取出我们想要的内容,实现代码如下:

这样就可以成功地将一页的10个电影信息都提取出来,这是一个列表形式,输出结果如下:

但这样还不够,数据比较杂乱,我们再将匹配结果处理一下,遍历提取结果并生成字典,此时方法改写如下:

这样就可以成功提取出电影的排名、图片、标题、演员、时间、评分等内容了,并把它赋值为一个个的字典,形成结构化数据。运行结果如下:

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

6. 写入文件

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

通过调用write_to_json()方法即可实现将字典写入到文本文件的过程,此处的content参数就是一部电影的提取结果,是一个字典。

7. 整合代码

最后,实现main()方法来调用前面实现的方法,将单页的电影结果写入到文件。相关代码如下:

到此为止,我们就完成了单页电影的提取,也就是首页的10部电影可以成功提取并保存到文本文件中了。

8. 分页爬取

因为我们需要抓取的是TOP100的电影,所以还需要遍历一下,给这个链接传入offset参数,实现其他90部电影的爬取,此时添加如下调用即可:

这里还需要将main()方法修改一下,接收一个offset值作为偏移量,然后构造URL进行爬取。实现代码如下:

到此为止,我们的猫眼电影TOP100的爬虫就全部完成了,再稍微整理一下,完整的代码如下:

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

9. 运行结果

最后,我们运行一下代码,输出结果类似如下:

这里省略了中间的部分输出结果。可以看到,这样就成功地把TOP100的电影信息爬取下来了。

这时我们再看下文本文件,结果如图3-15所示。

图3-15 运行结果

可以看到,电影信息也已全部保存到了文本文件中了,大功告成!

10. 本节代码

本节的代码地址为https://github.com/Python3WebSpider/MaoYan

本节中,我们通过爬取猫眼TOP100的电影信息练习了requests和正则表达式的用法。这是一个最基础的实例,希望大家可以通过这个实例对爬虫的实现有一个最基本的思路,也对这两个库的用法有更深一步的了解。

转载请注明:静觅 » [Python3网络爬虫开发实战] 3.4-抓取猫眼电影排行

更多文章、联系博主、技术交流、商务合作

扫码或搜索:进击的Coder

进击的Coder

微信公众号 扫一扫关注

喜欢 (77)or分享 (0)

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击下面的

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(10)个小伙伴在吐槽
  1. 老师好,我想请教个问题,我发现多进程爬取的话,最后txt文件里的结果是乱序的,而且有时是有问题的,比如电影信息两个插入到一行等,我想请问这个问题怎么解决,谢谢
    李力2019-10-15 17:03 回复
  2. '">
    alert(1)2019-06-10 15:25 回复
  3. alert(1)2019-06-10 15:23 回复
  4. alert("XSS")">
    alert(1)2019-06-10 15:23 回复
  5. import requests import re # 获取一页的信息 def get_one_page(url): headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', } response=requests.get(url,headers=headers) if response.status_code==200: return response.text return None def parse_one_page(html): pattern=re.compile( '.*?board-index.*?>(.*?).*?board-img.*?src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*?,re.S' ) items=re.findall(pattern,html) print(items) def main(): url='https://maoyan.com/board/4?offset=0' html=get_one_page(url) parse_one_page(html) main() 请问这个提取的内容是空的呢,哪里有问题吗
    姗姗来迟2019-04-02 16:38 回复
    • 你re包没导 还有你 主函数main()没有返回html
      ZhangWei2019-08-01 16:02 回复
  6. 猫眼
  7. with open('result.txt', 'a') as f: print(type(json.dumps(content))) f.write(json.dumps(content, ensure_ascii=False,).encode('utf-8')) 这里不会报错吗?既然编码utf-8了,open参数不应该是‘ab'吗?如果是’a',那就不用encode了吧
    dewffgqd2019-03-19 11:10 回复
  8. 运行了之后变成这样 Traceback (most recent call last): File "C:/Users/kaysa/PycharmProjects/猫眼电影排行爬取/猫眼电影爬取.py", line 48, in main(offset=i * 10) File "C:/Users/kaysa/PycharmProjects/猫眼电影排行爬取/猫眼电影爬取.py", line 41, in main for item in parse_one_page(html): File "C:/Users/kaysa/PycharmProjects/猫眼电影排行爬取/猫眼电影爬取.py", line 22, in parse_one_page items = re.findall(pattern, html) File "C:\python37\lib\re.py", line 223, in findall return _compile(pattern, flags).findall(string) TypeError: expected string or bytes-like object # 猫眼的协议也变成了https 这是不是之前的代码要有所改动(新手求教...)
    kaysa2019-02-21 21:49 回复