抓取网页新闻(新闻网站多如牛毛,我们该如何去爬呢?从哪里开爬呢?)
优采云 发布时间: 2022-01-31 07:19抓取网页新闻(新闻网站多如牛毛,我们该如何去爬呢?从哪里开爬呢?)
越来越多的人使用python编写爬虫,这也说明用python编写爬虫比其他语言更方便。很多新闻网站没有反爬策略,所以抓取新闻网站的数据比较方便。然而,消息网站铺天盖地,我们怎么爬呢?从哪里开始攀登?是我们需要考虑的第一个问题。
你需要的是异步IO来实现一个高效的爬虫。
让我们看看 Python3 的基于 asyncio 的新闻爬虫,以及我们如何高效地实现它。
从 Python3.5 开始,新增了一个语法,async 和 await 这两个关键字,asyncio 也成为了标准库,对我们编写异步 IO 的程序来说是一个很好的补充,让我们轻松实现一个用于有针对性的新闻抓取的异步爬虫。
1. 异步爬虫依赖的模块
asyncio:一个标准的异步模块,实现了python的异步机制;uvloop:C语言开发的异步循环模块,大大提高了异步机制的效率;aiohttp:用于下载网页的异步http请求模块;urllib.parse:解析url 网站的模块;logging:记录爬虫日志;leveldb:谷歌的Key-Value数据库,记录url的状态;farmhash:对url进行hash计算,作为url的唯一标识;sanicdb:封装了aiomysql,更方便的数据库mysql操作;2.异步爬虫实现流程2.1 消息源列表
本文要实现的异步爬虫是一个定向抓取新闻网站的爬虫,所以需要管理一个定向源列表,里面记录了很多我们要抓取的新闻网站的URL , 这些url指向的网页称为hub网页,它们具有以下特点:
Hub 网页是爬取的起点,爬虫从中提取新闻页面的链接,然后进行爬取。Hub URL可以存储在MySQL数据库中,运维可以随时添加或删除这个列表;爬虫会定期读取这个列表来更新目标爬取任务。这需要爬虫中的循环来定期读取中心 URL。
2.2 网址池
异步爬虫的所有过程都不是一个循环就能完成的,它是由多个循环(至少两个循环)交互完成的。它们之间的桥梁是“URL 池”(用 asyncio.Queue 实现)。
这个URL池就是我们比较熟悉的“生产者-消费者”模型。
一方面,hub URL会间隔进入URL池,爬虫从网页中提取的新闻链接也进入URL池,也就是产生URL的过程;
另一方面,爬虫需要从URL池中取出URL进行下载,这个过程就是消费过程;
两个进程相互配合,不断有url进出URL池。
2.3 数据库
这里使用了两个数据库:MySQL 和 Leveldb。前者用于保存中心 URL 和下载的网页;后者用于存储所有URL的状态(是否爬取成功)。
很多从网页中提取出来的链接可能已经被爬取过,不需要再次爬取,所以在进入URL池之前要进行检查,leveldb可以快速查看它们的状态。
3. 异步爬虫实现细节
前面爬虫过程中提到了两个循环:
周期 1:定期更新 hub网站 列表
async def loop_get_urls(self,):
print('loop_get_urls() start')
while 1:
await self.get_urls() # 从MySQL读取hub列表并将hub url放入queue
await asyncio.sleep(50)
循环 2:用于抓取网页的循环
async def loop_crawl(self,):
print('loop_crawl() start')
last_rating_time = time.time()
asyncio.ensure_future(self.loop_get_urls())
counter = 0
while 1:
item = await self.queue.get()
url, ishub = item
self._workers += 1
counter += 1
asyncio.ensure_future(self.process(url, ishub))
span = time.time() - last_rating_time
if span > 3:
rate = counter / span
print('\tloop_crawl2() rate:%s, counter: %s, workers: %s' % (round(rate, 2), counter, self._workers))
last_rating_time = time.time()
counter = 0
if self._workers > self.workers_max:
print('====== got workers_max, sleep 3 sec to next worker =====')
await asyncio.sleep(3)
4. 异步要点:
阅读 asyncio 的文档,了解它的运行过程。以下是您在使用它时注意到的一些事项。
(1)使用loop.run_until_complete(self.loop_crawl())启动整个程序的主循环;
(2)使用asyncio.ensure_future()异步调用一个函数,相当于gevent的多进程fork和spawn(),具体可以参考上面的代码。
文章首发于我的技术博客猿人学习Python基础教程