Python中如何编写一个简单的分布式定时爬虫
- 待抓取和已抓取(存放 url 的 hash )的 url 队列存储在 redis
+ 抓取结果放在 mongo
+ spider 和 master 之间用 rpc 框架通信( thrift 的 python 版本 thriftpy )
目前实现了是抓取点评 poi 详情页面的名称 地址 电话 3 个字段,后续再继续其他定下抓取的功能
项目地址: https://github.com/linzhi/minerva
爬虫的稳定性方面还有待提升,后续慢慢优化
Python中如何编写一个简单的分布式定时爬虫
有个问题请教下大家,仿照 https://github.com/xchaoinfo/fuck-login 写的知乎模拟登录,一直报验证码无效的 msg ,即使用个错误的密码也是报这个,代码在 https://github.com/linzhi/minerva/blob/master/minerva/zhihu.py ,不知道为啥呢
要写一个简单的分布式定时爬虫,可以用Celery + Redis + Beat的组合。这里给你一个完整可运行的示例:
首先安装依赖:
pip install celery redis requests beautifulsoup4
然后创建爬虫任务文件 crawler_tasks.py:
from celery import Celery
import requests
from bs4 import BeautifulSoup
import time
from datetime import timedelta
# 创建Celery应用,使用Redis作为消息代理
app = Celery('crawler_tasks',
broker='redis://localhost:6379/0',
backend='redis://localhost:6379/0')
# 爬虫任务
@app.task
def crawl_website(url):
"""爬取指定网页的任务"""
try:
print(f"开始爬取: {url}")
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# 这里简单提取标题作为示例
title = soup.title.string if soup.title else "无标题"
print(f"爬取完成: {url} - 标题: {title}")
return {
'url': url,
'title': title,
'status': 'success',
'timestamp': time.time()
}
except Exception as e:
print(f"爬取失败 {url}: {str(e)}")
return {
'url': url,
'error': str(e),
'status': 'failed',
'timestamp': time.time()
}
# 批量爬取任务
@app.task
def batch_crawl(urls):
"""批量爬取多个网页"""
results = []
for url in urls:
result = crawl_website.delay(url) # 异步执行
results.append(result)
return [result.get() for result in results]
创建定时任务配置 celery_config.py:
from datetime import timedelta
# Celery配置
broker_url = 'redis://localhost:6379/0'
result_backend = 'redis://localhost:6379/0'
# 定时任务配置
beat_schedule = {
'crawl-every-30-minutes': {
'task': 'crawler_tasks.crawl_website',
'schedule': timedelta(minutes=30), # 每30分钟执行一次
'args': ('https://example.com',), # 要爬取的URL
},
'daily-crawl': {
'task': 'crawler_tasks.batch_crawl',
'schedule': timedelta(days=1), # 每天执行一次
'args': ([
'https://news.example.com',
'https://blog.example.com',
'https://api.example.com/data'
],),
},
}
启动步骤:
- 启动Redis(如果还没启动):
redis-server
- 启动Celery worker(在不同机器或终端启动多个worker实现分布式):
# Worker 1
celery -A crawler_tasks worker --loglevel=info --hostname=worker1@%h
# Worker 2(在另一台机器或终端)
celery -A crawler_tasks worker --loglevel=info --hostname=worker2@%h
- 启动Celery beat(定时调度器):
celery -A crawler_tasks beat --loglevel=info
这个方案的核心优势:
- 分布式:可以启动多个worker在不同机器上并行处理任务
- 定时调度:通过Celery Beat实现灵活的定时任务
- 任务队列:Redis作为消息队列,任务自动分配给空闲worker
- 容错性:失败的任务可以重试,worker崩溃不影响整体系统
如果要扩展,可以:
- 添加任务结果存储到数据库
- 实现任务优先级
- 添加任务去重机制
- 配置任务重试策略
用Celery+Redis是Python分布式爬虫的经典方案。
知道原因了。。。获取验证码的 url https://www.zhihu.com/captcha.gif?r=1492661961962&type=login ,即使中间的参数 r (时间戳)是一样的,获取到的验证码也不一样
再次更新。。抓取知乎的问题&答案 不需要模拟登陆。。。。之前方向错了
我想问问为什么我写的爬虫运行一段时间就会报 requests.exceptions.ConnectionError: (‘Connection aborted.’, BadStatusLine("’’",)),用的 python 和 requests 库,我没有使用多线程,在请求之前都添加了 time.sleep(0.5) ,按说不至于请求太频繁啊,请问这个问题该怎么解决啊!谢谢了,找了好久答案也没辙
我看了那个解决方案,应该不是那个问题,要贴异常代码吗?还是程序代码?
Traceback (most recent call last):
File “zhihuSprider.py”, line 306, in <module>
sprider.bfs_search()
File “zhihuSprider.py”, line 286, in bfs_search
self.analyze_user(user_url, followee_url, follower_url)
File “zhihuSprider.py”, line 155, in analyze_user
result = json.loads(self.get_user_data(user_url))
File “zhihuSprider.py”, line 144, in get_user_data
response = self.session.get(url, headers=self.headers)
File “D:\Python27\lib\site-packages\requests<a target=”_blank" href=“http://sessions.py” rel=“nofollow noopener”>sessions.py", line 501, in get
return self.request(‘GET’, url, **kwargs)
File “D:\Python27\lib\site-packages\requests<a target=”_blank" href=“http://sessions.py” rel=“nofollow noopener”>sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File “D:\Python27\lib\site-packages\requests<a target=”_blank" href=“http://sessions.py” rel=“nofollow noopener”>sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File “D:\Python27\lib\site-packages\requests<a target=”_blank" href=“http://adapters.py” rel=“nofollow noopener”>adapters.py", line 473, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: (‘Connection aborted.’, BadStatusLine("’’",))
有代码链接么

