代码实现
import asyncio
import aiohttp
from bs4 import BeautifulSoup
import re
async def fetch(session, url, semaphore):
async with semaphore:
try:
async with session.get(url) as response:
if response.status == 200:
return await response.text()
else:
print(f"请求 {url} 失败,状态码: {response.status}")
return None
except Exception as e:
print(f"请求 {url} 时发生错误: {e}")
return None
async def parse(html, base_url, all_links, semaphore):
if not html:
return
soup = BeautifulSoup(html, 'html.parser')
# 提取文本内容
text = soup.get_text()
print(f"页面 {base_url} 的文本内容: \n{text}\n")
# 提取链接
for link in soup.find_all('a', href=True):
href = link['href']
if href.startswith('/'):
full_url = base_url + href
elif href.startswith('http'):
full_url = href
else:
continue
if full_url not in all_links:
all_links.add(full_url)
asyncio.create_task(fetch_and_parse(session, full_url, all_links, semaphore))
async def fetch_and_parse(session, url, all_links, semaphore):
html = await fetch(session, url, semaphore)
await parse(html, url, all_links, semaphore)
async def main(start_url):
all_links = set([start_url])
semaphore = asyncio.Semaphore(10) # 限制并发数
async with aiohttp.ClientSession() as session:
tasks = [fetch_and_parse(session, start_url, all_links, semaphore)]
await asyncio.gather(*tasks)
if __name__ == "__main__":
start_url = "https://example.com" # 替换为指定网站
asyncio.run(main(start_url))
采用的框架和技术原理
- 框架:
- aiohttp:用于处理异步HTTP请求。它基于Python的
asyncio
库,能充分利用异步I/O的优势,在等待网络响应时不阻塞主线程,大大提高爬虫的效率。通过ClientSession
管理HTTP会话,使用async with
语法进行异步请求操作。
- BeautifulSoup:用于解析HTML结构。它提供了简洁的API,能方便地定位和提取HTML中的各种元素,如标签、文本等。
- 技术原理:
- 异步请求:利用
asyncio
库实现异步编程。fetch
函数通过async with
语句发起异步HTTP请求,并等待响应。asyncio.create_task
用于创建新的任务,将请求和解析操作并发执行,提高爬取效率。
- 避免IP封禁:
- 限制并发数:通过
asyncio.Semaphore
设置并发请求的数量,避免短时间内对目标服务器发起过多请求,减轻服务器压力,降低被封禁的风险。
- 合理设置请求头:在实际应用中,可以在
aiohttp
的请求中设置合理的User - Agent
等请求头,模拟真实浏览器行为。
- 解析复杂的HTML结构:
- BeautifulSoup的灵活选择器:使用
find_all
等方法结合不同的选择器(如标签名、属性等)定位HTML元素。例如,通过find_all('a', href = True)
查找所有带有href
属性的a
标签,提取链接。
- 处理相对链接:将相对链接转换为绝对链接,确保能够正确访问页面。通过判断链接是否以
/
或http
开头,进行相应的处理。