抓取网页新闻(新闻网站多如牛毛,我们该如何去爬呢?从哪里开爬呢?)
优采云 发布时间: 2021-10-23 13:16抓取网页新闻(新闻网站多如牛毛,我们该如何去爬呢?从哪里开爬呢?)
用python写爬虫的人越来越多,这也说明用python写爬虫比其他语言更方便。很多新闻网站没有反爬虫策略,所以爬取新闻网站的数据比较方便。然而,这么多新闻网站,我们应该怎么爬?你从哪里开始?这是我们首先需要考虑的问题。
您需要的是异步 IO 来实现高效的爬虫。
下面我们来看看基于asyncio的Python3新闻爬虫,以及如何高效实现。
从 Python3.5 开始,增加了新的语法,关键字 async 和 await,asyncio 也成为了标准库。这与我们可以编写异步 IO 程序一样强大。让我们轻松实现一个。用于有针对性地抓取新闻的异步爬虫。
1. 异步爬虫依赖的模块
asyncio:标准异步模块,实现了python的异步机制;uvloop:C语言开发的异步循环模块,大大提高了异步机制的效率;aiohttp:用于下载网页的异步http请求模块;urllib.parse:解析url网站的模块;logging:记录爬虫日志;leveldb:Google 的 Key-Value 数据库,用于记录 URL 的状态;farmhash:将 URL 散列作为 URL 的唯一标识符;sanicdb:封装aiomysql,更方便的数据库mysql操作;2. 异步爬虫实现过程 2.1 新闻来源列表
本文要实现的异步爬虫是一个定向抓取新闻网站的爬虫,所以我们需要管理一个定向源列表,里面记录了很多我们想要的新闻网站的url抓住。这些URL指向的网页称为枢纽网页,它们具有以下特点:
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池之前必须进行检查,通过leveldb可以快速查看其状态。
3. 异步爬虫的实现细节
前面爬虫过程中提到了两个循环:
周期一:定期更新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)
循环二:抓取网页的循环
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 关键点:
阅读 asyncio 的文档以了解其运行过程。以下是您在使用时注意到的一些要点。
(1)使用loop.run_until_complete(self.loop_crawl())启动整个程序的主循环;
(2)使用asyncio.ensure_future()异步调用一个函数,相当于gevent的多进程fork和spawn(),具体可以参考上面的代码。
文章 首次发表在我的技术博客猿人学习Python基础教程