官方文檔:http://docs.pyspider.org/
中文網(wǎng)址:http://www.pyspider.cn/book/pyspider/
最新版本: https://github.com/binux/pyspider/releases
PySpider:一個(gè)國(guó)人編寫的強(qiáng)大的網(wǎng)絡(luò)爬蟲系統(tǒng)并帶有強(qiáng)大的WebUI。采用Python語(yǔ)言編寫权纤,分布式架構(gòu)国章,支持多種數(shù)據(jù)庫(kù)后端灭忠,強(qiáng)大的WebUI支持腳本編輯器区拳,任務(wù)監(jiān)視器谭确,項(xiàng)目管理器以及結(jié)果查看器刊橘。在線示例: http://demo.pyspider.org/
pyspider是作者之前做的一個(gè)爬蟲架構(gòu)的開(kāi)源化實(shí)現(xiàn)讲岁。主要的功能需求是:
抓取、更新調(diào)度多站點(diǎn)的特定的頁(yè)面
需要對(duì)頁(yè)面進(jìn)行結(jié)構(gòu)化信息提取
靈活可擴(kuò)展变汪,穩(wěn)定可監(jiān)控 而這也是絕大多數(shù)python爬蟲的需求 —— 定向抓取侠坎,結(jié)構(gòu)化化解析。但是面對(duì)結(jié)構(gòu)迥異的各種網(wǎng)站裙盾,單一的抓取模式并不一定能滿足实胸,靈活的抓取控制是必須的他嫡。為了達(dá)到這個(gè)目的,單純的配置文件往往不夠靈活庐完,于是钢属,通過(guò)腳本去控制抓取是我最后的選擇。 而去重調(diào)度门躯,隊(duì)列淆党,抓取,異常處理讶凉,監(jiān)控等功能作為框架染乌,提供給抓取腳本,并保證靈活性懂讯。最后加上web的編輯調(diào)試環(huán)境荷憋,以及web任務(wù)監(jiān)控,即成為了這套框架褐望。
pyspider的設(shè)計(jì)基礎(chǔ)是:以python腳本驅(qū)動(dòng)的抓取環(huán)模型爬蟲
通過(guò)python腳本進(jìn)行結(jié)構(gòu)化信息的提取勒庄,follow鏈接調(diào)度抓取控制,實(shí)現(xiàn)最大的靈活性
通過(guò)web化的腳本編寫瘫里、調(diào)試環(huán)境实蔽。web展現(xiàn)調(diào)度狀態(tài)
抓取環(huán)模型成熟穩(wěn)定,模塊間相互獨(dú)立谨读,通過(guò)消息隊(duì)列連接局装,從單進(jìn)程到多機(jī)分布式靈活拓展
安裝:
添加依賴
sudo apt-get install python python-dev python-distribute python-pip libcurl4-openssl-dev libxml2-dev libxslt1-dev python-lxml libssl-dev zlib1g-dev
sudo apt-get install phantomjs
pip3 install pyspider
啟動(dòng):
pyspider all
代碼實(shí)現(xiàn)
from pyspider.libs.base_handler import *
import pymongo,pymysql
class Handler(BaseHandler):
"""
Handler 就是 pyspider 爬蟲的主類,我
們可以在此處定義爬取漆腌、解析贼邓、存儲(chǔ)的邏輯阶冈。
整個(gè)爬蟲的功能只需要一個(gè) Handler 即可完成
"""
#crawl_config 屬性闷尿。我們可以將本項(xiàng)目的
#所有爬取配置統(tǒng)一定義到這里,如定義
#Headers女坑、設(shè)置代理等填具,配置之后全局生效
crawl_config = {
}
#mongodb數(shù)據(jù)庫(kù)連接
mongocli = pymongo.MongoClient(host='localhost', port=27017)
db = mongocli['jobbole']
jobbolearticle = db['jobbolearticle']
#mysql數(shù)據(jù)庫(kù)連接
client = pymysql.Connect(
'localhost','root','ljh1314',
'class1804',charset='utf8'
)
cursor = client.cursor()
#on_start() 方法是爬取入口,初始的爬取
#請(qǐng)求會(huì)在這里產(chǎn)生
@every(minutes=24 * 60)
def on_start(self):
self.crawl('http://blog.jobbole.com/all-posts/', callback=self.index_page)
@config(age=10 * 24 * 60 * 60)
def index_page(self, response):
print(response)
for each in response.doc('a[class="page-numbers"]').items():
self.crawl(each.attr.href, callback=self.detail_page)
@config(priority=2)
def detail_page(self, response):
self.index_page(response)
list = response.doc('#archive .post.floated-thumb')
# print(list)
for item in list.items():
print('拿到了數(shù)據(jù)')
print(type(item))
title = item('a.archive-title').text()
url = item('a.archive-title').attr.href
print(title,url)
return {
'title':title,
'url':url,
}
#方法中return的結(jié)果會(huì)執(zhí)行on_result
def on_result(self,result):
#可以在這里做數(shù)據(jù)的持久化
print(result)
#mysql數(shù)據(jù)庫(kù)存儲(chǔ)
sql = """
INSERT INTO jobbole()
VALUE (%s,%s)
"""
try:
self.cursor.execute(sql,[result['title'],result['url']])
self.client.commit()
except Exception as err:
print(err)
self.client.rollback()
#mongodb數(shù)據(jù)庫(kù)存儲(chǔ)
self.jobbolearticle.insert(result)