python 爬虫进阶

本项目仓库

在上上周我们了解了 python 爬虫的基本操作,这次就让小编带大家来了解更多的爬虫吧!

这次我们的目标也是两个:

  • 爬取 CSDN问答区精华版块的所有问答
  • 爬取 stackoverflow 的数据

CSDN精华

我们本次要爬取的网页

简单观察网页,我们会发现,随着页面往下滑动,会出现更多进入具体问答页面的链接。在控制台中的 Elements 项中,也能观察到出现了更多的类似于 <div class="question-content-wrapper" data-v-09010672="" data-v-2e2ddf27=""></div> 的标签。但当我们进入 network 项中,却发现并没有能够得到相关的数据。因此,这和上次下滑出现更多页面的分 p 发包的原理不同,这些链接是通过页面的滑动,用 js 动态渲染出来的,和上次的答案部分一样。

当然,我们的爬虫技艺也不会止步于此。既然能在 Elements 中看到,那想必还是有办法爬取的。之前我们爬虫利用的原理是发送请求后从返回的响应中找信息。那能不能让爬虫直接像我们平时使用浏览器一样获得最后渲染出的页面呢?

自然是可以的。这次我们使用的原理就是在爬虫中模拟一个浏览器,通过浏览器打开页面,来直接得到页面中显示的所有数据。而这些自然也是有很多造好了的轮子。一个非常经典的便是 selenuim 。可以参考入门指南。但小编这里用的不是这个,而是另一个更加新一点的,叫做 playwright。学习资料参考 这篇文章。同时这里是 api 文档

于是,我们可以在模拟的浏览器中打开刚刚的 CSDN 精华 的网页了。并且,阅读 api 文档后,我们发现可以用 page.mouse.wheel() 函数来模拟鼠标滚轮。接下来,只需要一直滑动到页面底端爬取所有进入具体问答页面的链接就行了。

在此过程中,有两种选择:一种在一边滚轮的同时一边进入得到的链接并爬去具体信息;另一种则是先滚到底部,爬取所有的链接并存入文件中。接下来我们只需要在那个文件中读入所有链接就能进行后续的爬取。在写爬虫时,调试也是经常需要遇到的,所有我觉得这里第二种更优,毕竟鼠标滚轮滚完一遍后,就不需要再进行这样的操作了。否则,我们反复运行程序调试,每次都要一遍滚一边爬,还是比较麻烦。

在获得所有链接后,接下来就是进入链接爬取问答详情了。由于我们已经有了模拟浏览器的手段,动态渲染的答案对我们来说也已经不算问题。但当我们尝试用之前的 asyncio 进行并发爬取时,至少小编的电脑是直接炸了。原来当我们把所有链接加入任务后,如果没有限制,爬下来的链接数量是 3000 左右,则相当于有 3000 个任务并发。于是一种处理的手段是利用信号量(Semaphore)来限制并发的数量。这自然是可行的。

更多并发的方式

不过,除了协程,还有其他并发的手段,那就是多线程和多进程。

多线程

参考

多进程

参考

学会了这些手段后,我们的爬虫优化也能变得更加多样。

stackoverflow

这个网站的爬取将更加艰难,因为它设置了一些反爬虫的机制。

但我们还是先把爬虫的大体思路梳理一下。进入网站后,由于这是全英文的,所有需要先翻译我们要搜索的关键词。接下来,搜索关键词,我们会要进行一步人机验证。之后的感觉就和上上周的 CSDN 一样了。我们获得进入详情页面的链接,再在详情页获取具体的问答信息即可。在这里我们选择下方的第一个回答作为答案。

但问题是,我们的爬虫无法完成人机验证。这也就意味着无法进入搜索关键词后显示所有具体链接的页面。此时似乎陷入了僵局。但在多次访问和搜索后,发现在进行一次人机验证后的一段时间内,搜索将不需要进行人机验证。而更具体地,不需要进行验证的时间为五分钟。所以一个简单的想法就是我们在浏览器中手动点一下人机验证,然后让爬虫爬五分钟,再手动点一下,以此循环。但在大量数据面前,这对我们而言似乎不太友好。

于是,我们希望能提升爬虫的速度,让它在五分钟内能爬尽量多的数据。但当我们上了高并行的爬虫后,我们发现没过多久爬虫就收不到响应了。进入浏览器再人工查看网页,会有一个提示,说我们的 ip 在同一时间发送了太多请求,这是不正常的,所以把我们的 ip 封了。

这个问题理论上可以通过 ip 池随机代理来解决,但是处理起来比较困难。而经过探索,我们发现,只有搜索关键词后才会跳转人机验证,而进入具体问答页面的链接是不会跳人机验证的。再联系上文 CSDN 精华的处理方式,便能得到一个简单点的想法。首先我们以人工辅助人机验证的方式来为爬虫获取五分钟时间,在这五分钟内只把跳转问答详情页的链接爬下来并存在文件中。获取所有链接后,我们的爬虫便能以一个合理的速度,慢慢地,不被封 ip 地爬取所有的详情问答了。

scrapy 框架

scrapy 是一个实现的框架。参考:

赞赏