最近在做一个需要批量采集网页数据的项目,发现了crawl4ai这个基于Docker的网页爬取工具。它的REST API接口设计得非常灵活,特别是支持通过JSON配置来实现各种复杂的爬取需求。经过一段时间的摸索,我总结出一套实用的配置方案,今天就来分享下如何通过Python调用这个API实现高效的数据采集。
先看下这个工具的核心优势:
首先需要拉取官方镜像并启动服务:
bash复制docker pull crawl4ai/crawl4ai:latest
docker run -d -p 11235:11235 --name crawl4ai crawl4ai/crawl4ai
这个命令会在本地11235端口启动API服务。如果需要在生产环境使用,建议添加--restart always参数确保服务自动重启。
API的核心请求体是一个JSON结构,主要包含三个部分:
python复制payload = {
"urls": [], # 待爬取的URL列表
"browser_config": {}, # 浏览器行为配置
"crawler_config": {} # 爬取过程配置
}
浏览器配置的完整结构如下:
python复制"browser_config": {
"type": "BrowserConfig",
"params": {
"headless": True, # 是否启用无头模式
"viewport": {
"type": "dict",
"value": {
"width": 1200, # 视窗宽度
"height": 800 # 视窗高度
}
}
}
}
实际测试中发现,某些网站会根据视窗大小返回不同的布局。建议PC端采集设置为1200×800,移动端可设置为375×667。
还可以通过extra_params传递更多底层配置:
python复制"params": {
"timeout": 30000, # 页面加载超时(毫秒)
"user_agent": "Mozilla/5.0...", # 自定义UA
"proxy": "http://proxy.example.com:8080" # 代理设置
}
python复制"crawler_config": {
"type": "CrawlerRunConfig",
"params": {
"cache_mode": "bypass", # bypass|force|normal
// 其他配置...
}
}
python复制"markdown_generator": {
"type": "DefaultMarkdownGenerator",
"params": {
"options": {
"type": "dict",
"value": {
"ignore_links": True, # 过滤所有超链接
"ignore_images": True, # 过滤图片
"escape_html": False, # 是否转义HTML标签
"content_selectors": [".article"] # 仅抓取指定元素
}
}
}
}
使用Python的aiohttp库可以实现高效的并发请求:
python复制async def crawl_task(session, url):
payload['urls'] = [url]
async with session.post(API_ENDPOINT, json=payload) as resp:
return await resp.json()
async def batch_crawl(urls):
async with aiohttp.ClientSession() as session:
tasks = [crawl_task(session, url) for url in urls]
return await asyncio.gather(*tasks)
建议添加重试逻辑和错误处理:
python复制async def crawl_with_retry(session, url, retries=3):
for attempt in range(retries):
try:
return await crawl_task(session, url)
except Exception as e:
if attempt == retries - 1:
raise
await asyncio.sleep(2 ** attempt) # 指数退避
连接池配置:在ClientSession中设置连接限制
python复制connector = aiohttp.TCPConnector(limit=20)
async with aiohttp.ClientSession(connector=connector) as session:
超时设置:避免单个请求阻塞整个流程
python复制timeout = aiohttp.ClientTimeout(total=30)
async with session.post(..., timeout=timeout)
问题1:返回结果为空
问题2:请求超时
通过定时任务+API调用,可以实现:
将原始HTML转换为标准Markdown后:
这套方案在我们团队已经稳定运行了半年多,日均处理10万+页面。最关键的是要根据实际业务需求调整浏览器参数和爬取策略。比如对电商网站需要禁用图片加载,对新闻站点则要保留完整的文本结构。