如何实现新闻网站全异步爬取?列表页与文章爬取并发方案
异步新闻爬虫优化实现
核心问题分析
当前代码中的get_urls是阻塞调用,导致列表页请求必须等待当前页所有文章爬取完成后才能执行,无法发挥异步IO的并发优势。需要将get_urls改造为异步函数,并调整任务调度逻辑,让下一页列表请求与当前页文章爬取并行执行。
步骤1:将get_urls改造为异步函数
使用aiohttp发送异步GET请求,解析HTML获取新闻链接和下一页URL(示例基于BeautifulSoup,可根据实际网站结构调整解析逻辑):
import asyncio import aiohttp from bs4 import BeautifulSoup TAG_URL = "https://example.com/news/category/{}" # 替换为目标网站的分类URL模板 async def get_urls(session: aiohttp.ClientSession, url: str) -> tuple[list[str], str | None]: """异步获取新闻链接和下一页URL""" async with session.get(url) as resp: if not resp.ok: resp.raise_for_status() html = await resp.text() soup = BeautifulSoup(html, "html.parser") # 解析新闻详情页链接(替换为目标网站的CSS选择器) news_urls = [a["href"] for a in soup.select("div.news-item a.title")] # 解析下一页URL(替换为目标网站的下一页按钮选择器) next_page_elem = soup.select_one("a.next-page") next_url = next_page_elem["href"] if next_page_elem else None return news_urls, next_url
步骤2:优化主逻辑实现并发
调整任务调度,让列表页请求与文章爬取任务并行执行,无需等待当前页所有文章爬完再请求下一页:
async def parse_page(session: aiohttp.ClientSession, url: str, semaphore: asyncio.Semaphore): """异步爬取单篇新闻详情页(示例逻辑,需根据需求修改)""" async with semaphore: async with session.get(url) as resp: if not resp.ok: print(f"Failed to fetch {url}: {resp.status}") return article_html = await resp.text() # 解析文章标题、内容等逻辑... print(f"Successfully crawled {url}") async def main(): # 限制并发请求数,避免触发反爬 semaphore = asyncio.Semaphore(15) tasks = [] async with aiohttp.ClientSession() as session: current_url = TAG_URL.format("economy") while current_url: # 异步获取当前页新闻链接和下一页URL news_urls, current_url = await get_urls(session, current_url) # 为当前页所有新闻创建爬取任务 for url in news_urls: task = asyncio.create_task(parse_page(session, url, semaphore)) tasks.append(task) # 等待所有爬取任务完成 await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(main())
关键优化点
- 全异步IO:所有网络请求均使用
aiohttp异步实现,避免阻塞事件循环。 - 并发调度:获取当前页新闻链接后,立即启动下一页的列表请求,同时当前页的文章爬取任务在后台执行,大幅提升爬取效率。
- 并发量控制:通过
asyncio.Semaphore限制同时发起的请求数,降低被网站封禁的风险。
内容的提问来源于stack exchange,提问作者Deeproad
相关产品推荐
相关产品推荐

