spiderman
基于 scrapy-redis 的通用分布式爬蟲框架
開源地址 https://github.com/TurboWay/spiderman
目錄
demo采集效果
爬蟲元數(shù)據(jù)
cluster模式
standalone模式
附件下載
kafka實(shí)時采集監(jiān)控
功能
自動建表
自動生成爬蟲代碼收壕,只需編寫少量代碼即可完成分布式爬蟲
自動存儲元數(shù)據(jù)蒋得,分析統(tǒng)計和補(bǔ)爬都很方便
適合多站點(diǎn)開發(fā)窝稿,每個爬蟲獨(dú)立定制籽腕,互不影響
調(diào)用方便础废,可以根據(jù)傳參自定義采集的頁數(shù)以及啟用的爬蟲數(shù)量
擴(kuò)展簡易姑尺,可以根據(jù)需要選擇采集模式厂抖,單機(jī) standalone (默認(rèn)) 或者 分布式cluster
-
采集數(shù)據(jù)落地方便灸眼,支持多種數(shù)據(jù)庫卧檐,只需在 spider 中啟用相關(guān)的管道
關(guān)系型
- mysql
- sqlserver
- oracle
- postgresql
- sqlite3
非關(guān)系型
- hbase
- mongodb
- elasticsearch
- hdfs
- hive
- datafile, 比如 csv
-
反爬處理簡易,已封裝各種反爬中間件
- 隨機(jī) UserAgent
- 定制請求頭 Headers
- 定制 Cookies 池
- 定制代理 ip
- 在 scrapy 中使用 requests
- Payload 請求
- 使用 Splash 渲染 js
原理說明
- 消息隊列使用 redis幢炸,采集策略使用廣度優(yōu)先泄隔,先進(jìn)先出
- 每個爬蟲都有一個 job 文件,使用 job 來生成初始請求類 ScheduledRequest宛徊,并將其推送到 redis佛嬉;
初始請求全部推到 redis 后,運(yùn)行 spider 解析生成數(shù)據(jù) 并迭代新的請求到redis, 直到 redis 中的全部請求被消耗完
# scrapy_redis請求類
class ScheduledRequest:
def __init__(self, **kwargs):
self.url = kwargs.get('url') # 請求url
self.method = kwargs.get('method', 'GET') # 請求方式 默認(rèn)get
self.callback = kwargs.get('callback') # 回調(diào)函數(shù)闸天,指定spider的解析函數(shù)
self.body = kwargs.get('body') # body, method為post時, 作為 post表單
self.meta = kwargs.get('meta') # meta, 攜帶元數(shù)據(jù)暖呕,比如 pagenum
- item 類定義表名、字段名苞氮、排序號(自定義字段順序)湾揽、注釋說明(便于管理元數(shù)據(jù))、字段類型(僅關(guān)系型數(shù)據(jù)庫管道有效)
class zhifang_list_Item(scrapy.Item):
# define table
tablename = 'zhifang_list'
tabledesc = '列表'
# define the fields for your item here like:
# 關(guān)系型數(shù)據(jù)庫,可以自定義字段的類型库物、長度霸旗,默認(rèn) VARCHAR(length=255)
# colname = scrapy.Field({'idx': 1, 'comment': '名稱', 'type': VARCHAR(255)})
tit = scrapy.Field({'idx': 1, 'comment': '房屋標(biāo)題'})
txt = scrapy.Field({'idx': 2, 'comment': '房屋描述'})
tit2 = scrapy.Field({'idx': 3, 'comment': '房屋樓層'})
price = scrapy.Field({'idx': 4, 'comment': '房屋價格'})
agent = scrapy.Field({'idx': 5, 'comment': '房屋中介'})
# default column
detail_full_url = scrapy.Field({'idx': 100, 'comment': '詳情鏈接'}) # 通用字段
pkey = scrapy.Field({'idx': 101, 'comment': 'md5(detail_full_url)'}) # 通用字段
pagenum = scrapy.Field({'idx': 102, 'comment': '頁碼'}) # 通用字段
- 去重策略,默認(rèn)不去重戚揭,每次采集獨(dú)立诱告,即每次啟動 job 都會清空上一次未完成的 url,并且不保留 redis 中上一次已采集的 url 指紋民晒。
如需調(diào)整可以修改以下配置
- job 文件(單個爬蟲)
class zhifang_job(SPJob):
def __init__(self):
super().__init__(spider_name=zhifang_Spider.name)
# self.delete() # 如需去重精居、增量采集,請注釋該行
- spider 文件(單個爬蟲)
custom_settings = {
...,
'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter',
'SCHEDULER_PERSIST': True, # 開啟持久化
}
def get_callback(self, callback):
# url去重設(shè)置:True 不去重 False 去重
callback_dt = {
'list': (self.list_parse, False),
'detail': (self.detail_parse, False),
}
return callback_dt.get(callback)
- 布隆過濾器潜必。
當(dāng)采集的數(shù)據(jù)量很大時靴姿,可以使用布隆過濾器,該算法占用空間小且可控磁滚,適合海量數(shù)據(jù)去重佛吓。
但是該算法會有漏失率,對爬蟲而言就是漏爬恨旱”蔡海可以通過調(diào)整過濾器負(fù)載個數(shù)、內(nèi)存配置搜贤、哈希次數(shù)以降低漏失率谆沃。
默認(rèn) 1 個過濾器,256 M 內(nèi)存仪芒,使用 7 個 seeds唁影,這個配置表示漏失概率為 8.56e-05 時,可滿足 0.93 億條字符串的去重掂名。當(dāng)漏失率為 0.000112 時据沈,可滿足 0.98 億條字符串的去重。調(diào)參與漏失率參考
custom_settings = {
...,
'DUPEFILTER_CLASS': 'SP.bloom_dupefilter.BloomRFDupeFilter', # 使用布隆過濾器
'SCHEDULER_PERSIST': True, # 開啟持久化
'BLOOM_NUM': 1, # 布隆過濾器負(fù)載個數(shù)饺蔑,當(dāng)內(nèi)存達(dá)到限制時锌介,可以增加負(fù)載個數(shù)
'BLOOM_MEM': 256, # 布隆過濾器內(nèi)存大小(單位 M)猾警,內(nèi)存最大 512 M (因為 redis string 最大只能 512 M)
'BLOOM_K': 7, # 布隆過濾器哈希次數(shù)孔祸,次數(shù)越少,去重越快发皿,但是漏失率越高
}
def get_callback(self, callback):
# url去重設(shè)置:True 不去重 False 去重
callback_dt = {
'list': (self.list_parse, False),
'detail': (self.detail_parse, False),
}
return callback_dt.get(callback)
下載安裝
- git clone https://github.com/TurboWay/spiderman.git; cd spiderman;
- 【不使用虛擬環(huán)境的話崔慧,可以跳過步驟23】virtualenv -p /usr/bin/python3 venv
- 【不使用虛擬環(huán)境的話,可以跳過步驟23】source venv/bin/activate
- pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
- 修改配置 vi SP/settings.py
- 運(yùn)行demo示例 python SP_JOBS/zhifang_job.py
如何開發(fā)一個新爬蟲
運(yùn)行 easy_scrapy.py 會根據(jù)模板自動生成以下代碼文件穴墅,并自動在編輯器打開 spidername_job.py 文件惶室;
類別 | 路徑 | 說明 |
---|---|---|
job | SP_JOBS/spidername_job.py | 編寫初始請求 |
spider | SP/spiders/spidername.py | 編寫解析規(guī)則温自,產(chǎn)生新的請求 |
items | SP/items/spidername_items.py | 定義表名字段 |
以上代碼文件編寫完成后,直接執(zhí)行 python SP_JOBS/spidername_job.py
或者動態(tài)傳參(參數(shù)說明 -p 采集頁數(shù)皇钞, -n 啟用爬蟲數(shù)量) python SP_JOBS/spidername_job.py -p 10 -n 1
如何進(jìn)行補(bǔ)爬
運(yùn)行 easy_scrapy.py 會根據(jù)模板自動生成以下代碼文件悼泌,并自動在編輯器打開 spidername_job_patch.py 文件;
類別 | 路徑 | 說明 |
---|---|---|
job | SP_JOBS/spidername_job_patch.py | 編寫補(bǔ)爬請求 |
以上代碼文件編寫完成后鹅士,直接執(zhí)行 python SP_JOBS/spidername_job_patch.py
如何下載附件
提供兩種方式下載:
- 1券躁、直接在 spider 中啟用附件下載管道
- 2、使用自定義的下載器 execute_download.py 傳參下載
jpg/pdf/word...等各種各樣的文件掉盅,統(tǒng)稱為附件。
下載附件是比較占用帶寬的行為以舒,所以在大規(guī)模采集中趾痘,最好是先把結(jié)構(gòu)化的表數(shù)據(jù)、附件的元數(shù)據(jù)入庫蔓钟,
保證數(shù)據(jù)的完整性永票,然后再根據(jù)需要,通過下載器進(jìn)行附件下載滥沫。
如何擴(kuò)展分布式爬蟲
采集模式有兩種(在 settings 控制): 單機(jī) standalone(默認(rèn)) 和 集群分布式
如果想切換成分布式爬蟲侣集,需要在 spiderman/SP/settings.py 中啟用以下配置
<font color='red'> 注意:前提是 所有SLAVE機(jī)器的爬蟲代碼一致、python環(huán)境一致兰绣,都可以運(yùn)行爬蟲demo </font>
# 集群模式 False 單機(jī) (默認(rèn)); True 分布式 需要配置下方的 slaves
CLUSTER_ENABLE = True
配置名稱 | 意義 | 示例 |
---|---|---|
SLAVES | 【二選一】爬蟲機(jī)器配置列表 | [{'host': '172.16.122.12', 'port': 22, 'user': 'spider', 'pwd': 'spider'}世分, {'host': '172.16.122.13', 'port': 22, 'user': 'spider', 'pwd': 'spider'} ] |
SLAVES_BALANCE | 【二選一】爬蟲機(jī)器配置(ssh負(fù)載均衡) | {'host': '172.16.122.11', 'port': 2202, 'user': 'spider', 'pwd': 'spider'} |
SLAVES_ENV | 【可選】爬蟲機(jī)器虛擬環(huán)境路徑 | /home/spider/workspace/spiderman/venv |
SLAVES_WORKSPACE | 【必填】爬蟲機(jī)器代碼工程路徑 | /home/spider/workspace/spiderman |
如何管理爬蟲元數(shù)據(jù)
運(yùn)行 easy_meta.py 自動生成當(dāng)前項目所有爬蟲的元數(shù)據(jù), 默認(rèn)記錄到sqlite meta.db, 可以在 setting 中自行配置;
# 爬蟲 meta
META_ENGINE = 'sqlite:///meta.db'
元數(shù)據(jù)表meta字典如下:
字段名 | 類型 | 注釋 |
---|---|---|
spider | varchar(50) | 爬蟲名 |
spider_comment | varchar(100) | 爬蟲描述 |
tb | varchar(50) | 表名 |
tb_comment | varchar(100) | 表描述 |
col_px | int | 字段序號 |
col | varchar(50) | 字段名 |
col_comment | varchar(100) | 字段描述 |
author | varchar(20) | 開發(fā)人員 |
addtime | varchar(20) | 開發(fā)時間 |
insertime | varchar(20) | 元數(shù)據(jù)更新時間 |
如何配合kafka做實(shí)時采集監(jiān)控
- 配置 kafka(修改 setting 的 KAFKA_SERVERS)
- 自定義監(jiān)控規(guī)則(修改編寫 kafka_mon.py , 并運(yùn)行該腳本程序, 開始監(jiān)控)
- 在 spider 中啟用 kafka 管道(運(yùn)行爬蟲 job , 開始采集)
如何使用爬蟲api
直接運(yùn)行 api.py,然后可以通過 http://127.0.0.1:2021/docs 查看相關(guān)的 api 文檔
注意事項
- 字段名稱不能使用 tablename缀辩、isload臭埋、ctime、bizdate臀玄、spider 等字段瓢阴,因為這些字段被作為通用字段,避免沖突
- items 文件每個字段建議添加注釋健无,生成元數(shù)據(jù)時荣恐,會將注釋導(dǎo)入到元數(shù)據(jù)表,便于管理爬蟲
hive環(huán)境問題
在 windows 環(huán)境下累贤,使用 python3 連接 hive 會有很多坑叠穆,所以使用 hdfs 管道時,hive 自動建表功能默認(rèn)關(guān)閉畦浓,便于部署痹束。
假如需要啟用 hive 自動建表功能,請進(jìn)行如下操作:
- pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
- pip install --no-deps thrift-sasl==0.2.1
- 驗證環(huán)境讶请,執(zhí)行 SP.utils.ctrl_hive
如果執(zhí)行成功祷嘶,說明 hive 環(huán)境準(zhǔn)備完畢屎媳,可以直接啟用 hive 自動建表功能;如果遇到問題论巍,可以參考 【大數(shù)據(jù)】windows 下python3連接hive
更新日志
日期 | 更新內(nèi)容 |
---|---|
20200803 | 1.使用更優(yōu)雅的方式來生成元數(shù)據(jù); 2.管道函數(shù)傳參的寫法調(diào)整; 3.附件表通用字段更名:下載狀態(tài) (isload => status) |
20200831 | 1.解決數(shù)據(jù)入庫失敗時烛谊,一直重試入庫的問題; 2.所有管道優(yōu)化,入庫失敗時嘉汰,自動切換成逐行入庫丹禀,只丟棄異常記錄 |
20201104 | 1.requests 中間件支持 DOWNLOAD_TIMEOUT、DOWNLOAD_DELAY |
20201212 | 1.payload 中間件支持 DOWNLOAD_TIMEOUT鞋怀、DOWNLOAD_DELAY; 2.get_sp_cookies 方法優(yōu)化双泪,使用輕量級的 splash 替換 selenium; 3.md 的原理部分增加去重策略的說明 |
20210105 | 1.增加布隆過濾器 |
20210217 | 1.elasticsearch 管道調(diào)整,兼容 elasticsearch7 以上版本密似,直接使用表名作為索引名 |
20210314 | 1.所有反爬中間件合并到 SPMiddleWare |
20210315 | 1.使用更優(yōu)雅的方式生成 job 初始請求; 2.headers 中間件優(yōu)化焙矛,減少 redis 的內(nèi)存占用; 3.刪除 cookie 中間件,cookie 只是 headers 里面的一個值残腌,可以直接使用 headers 中間件; 4.刪除 Payload 中間件村斟,Payload 請求可以直接使用 requests 中間件 5.增加 CookiesPool 中間件,用于需要多個賬號隨機(jī)切換采集的場景 |
20210317 | 1.增加可以脫離 scrapy 獨(dú)立工作的抛猫、支持分布式的附件下載器 |
20210318 | 1.增加 api 服務(wù) |