首先來看一下一個爬蟲平臺的設計,作為一個爬蟲平臺,需要支撐多種不同的爬蟲方式,所以一般爬蟲平臺需要包括
1、 爬蟲規則的維護,平臺在接收到爬蟲請求時,需要能按照匹配一定的規則去進行自動爬蟲
2、 爬蟲的job排程器,平臺需要能負責爬蟲任務的排程,比如定時排程,輪訓排程等。
3、 爬蟲可以包括非同步的海量爬蟲,也可以包括實時爬蟲,非同步爬蟲指的是爬蟲的資料不會實時返回,可能一個爬蟲任務會執行很久。 實時爬蟲指爬的資料要實時返回,這個就要求時間很短,一般適合少量資料的爬蟲。
4、 爬蟲好的資料可以生成指定的檔案,比如csv檔案,json檔案等,然後通過資料處理引擎做統一處理,比如csv檔案可以通過資料交換落入大資料平臺,或者爬蟲好的資料也可以丟入kafka中,然後再通過流式處理任務(spark或者storm,flink)做爬蟲資料的清洗和處理,處理完的資料,可以入到資料庫中。
下圖就是在平臺設計時,爬蟲處理的一個流程,這個裡面包含了實時爬蟲,非同步爬蟲。
我們這裡先介紹非同步爬蟲,爬蟲的框架很多,非同步爬蟲一般用的比較多就是scrapy。
首先安裝scrapy
pip install scrapy
安裝完成後,就可以通過命令列建立一個基於scrapy的爬蟲專案
scrapy startproject zj_scrapy
然後在命令列中,進入到建立的zj_scrapy目錄下
cd zj_scrapy
執行
scrapy genspider sjqq “sj.qq.com”
建立一個爬蟲
爬蟲建立好了後,可以使用IDE開啟建立好的python專案,比如用idea(需要安裝python外掛,預設沒有安裝)開啟我們建立好的專案
專案建立好了後,會預設生成一些模板程式碼檔案
1、 items.py
items用於儲存欄位的定義。即爬取的內容存與item類中,在這裡我們定義了一個name欄位。
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class ZjScrapyItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() name = scrapy.Field() pass
2、 spider檔案編寫
這個檔案一般在spiders 這個package下面,預設會繼承scrapy.Spider
# -*- coding: utf-8 -*- import scrapy from scrapy.http import HtmlResponse from zj_scrapy.items import ZjScrapyItem class SjqqSpider(scrapy.Spider): name = 'sjqq' allowed_domains = ['sj.qq.com'] start_urls = ['https://sj.qq.com/myapp/category.htm?orgame=1&categoryId=114'] def parse(self, response:HtmlResponse): name_list = response.xpath('/html/body/div[3]/div[2]/ul/li') print("=============",response.headers) for each in name_list: item = ZjScrapyItem() name = each.xpath('./div/div/a[1]/text()').extract() item['name'] = name[0] yield item pass
關於這段程式碼的解釋如下:
3、 pipeline檔案編寫
pipeline檔案一般用於對處理好的爬蟲結果資料做處理,可以入到資料庫中,也可以生成到指定的檔案中,process_item 方法就是對資料做處理的。
另外pipeline 還包含了__init__和close_spider 兩個方法。__init__ 用於做初始化處理。 close_spider 用於執行結束時的操作處理。比如資料寫入資料庫或者檔案後,對資料庫做連結關閉或者檔案流做關閉操作等。
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html class ZjScrapyPipeline(object): def process_item(self, item, spider): print("+++++++++++++++++++",item['name']) print("-------------------",spider.cc) return item
4、 setting檔案修改
setting檔案中存放的是爬蟲的配置,常用的配置一般可以包括
1)、ITEM_PIPELINES的配置,比如
ITEM_PIPELINES = {
'zj_scrapy.pipelines.ZjScrapyPipeline': 300,
}
這裡的300代表了一個優先順序,數值範圍一般在0-1000,這個數值確定了執行的順序,數字越小,優先順序越高。
2)、字符集配置,可以通過FEED_EXPORT_ENCODING指定字符集
FEED_EXPORT_ENCODING = 'utf-8'
3)、CONCURRENT_REQUESTS配置Scrapy執行的最大併發請求數
# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 32
4)配置請求的header,可以通過DEFAULT_REQUEST_HEADERS來進行配置
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
5、 本地執行爬蟲
在上面的都做完後,可以通過執行命令列scrapy crawl sjqq -o items.csv 來在本地執行爬蟲,sjqq 就是前面指定的爬蟲名,-o items.csv 表示生成一個csv檔案。
執行完成後,可以看到爬取的內容已經寫到了指定的檔案中。
在執行時,可以通過-a 指定自定義的引數,比如scrapy crawl sjqq -o items.csv -a cc=scrapttest
在這條執行命令中,我們指定了一個cc引數等於scrapttest,在Pipeline
中,我們可以通過程式碼獲取這個引數
class ZjScrapyPipeline(object): def process_item(self, item, spider): print("+++++++++++++++++++",item['name']) print("-------------------",spider.cc) return item
在程式碼中,我們通過spider.cc 就可以獲取到這個引數的值,然後在執行日誌可以看到,我們列印出來了這個引數值。
通過這種方式,我們就解決了爬蟲執行時,引數的的動態傳遞問題。
6、 爬蟲部署到服務端
安裝scrapyd
pip install scrapyd
安裝scrapyd-deploy
pip install scrapyd-client
scrapyd 是scrapy的爬蟲服務端,安裝完成後,執行scrapyd可以啟動服務端。
啟動時預設埠為6800
啟動後,通過瀏覽器可以訪問http://localhost:6800/
服務端啟動後,就可以通過scrapyd-deploy 來提交部署開發好的爬蟲了。
scrapyd-deploy <target> -p <project> --version <version>
部署成功後,就可以看到自己的爬蟲專案了
7、 建立服務端的爬蟲任務
如果是在linux命令下,可以通過
curl http://localhost:6800/schedule.json -d project= zj_scrapy -d spider=sjqq
來提交一個爬蟲任務,提交完成後,會返回提交的任務狀態,這個其實就是提交了一個http請求
{
"node_name": "ZJPH-0321",
"status": "ok",
"jobid": "dd7f10aca76e11e99b656c4b90156b7e"
}
提交成功後,可以在瀏覽器的job下面看到任務的執行情況
如果需要攜帶自定義的引數,那麼可以通過-d來指定,比如-d cc=scrapttest,和前面在本地執行時,增加自定義引數是一樣的。
也可以通過http請求工具(比如soapui)提交一個http請求來觸發一個爬蟲任務
schedule.json請求中還可以包含如下引數
setting (string, optional) –自定義爬蟲settings
jobid (string, optional) –jobid,之前啟動過的spider,會有一個id,這個是可選引數
_version (string, optional) –版本號,之前部署的時候的version,只能使用int資料型別,沒指定,預設啟動最新版本
8、 scrapyd 其他的API
1)、curl http://localhost:6800/daemonstatus.json 檢查爬蟲服務的狀態
2)、addversion.json增加專案到服務端 如果專案已經存在,則增加一個新的版本
POST請求:
project (string, required) –專案名
version (string, required) –專案版本,不填寫則是當前時間戳
egg (file, required) –當前專案的egg檔案
curl http://localhost:6800/addversion.json -F project=myproject -F version=r23 -F egg=@myproject.egg
3)、 cancel.json
取消一個 spdier的執行
如果 spider是執行狀態,則停止其執行
如果 spider是掛起狀態,則刪除spider
POST請求:
project (string, required) –專案名
job (string, required) -jobid
curl http://localhost:6800/cancel.json -d project=myproject -d job=6487ec79947edab326d6db28a2d86511e8247444
4)、listprojects.json
獲取當前已上傳的專案的列表
GET請求:
curl http://localhost:6800/listprojects.json
5)、listversions.json
獲取指定專案的可用版本
GET請求:
project (string, required) –專案名
curl http://localhost:6800/listversions.json?project=myproject
6)、listspiders.json
獲取指定版本的專案中的爬蟲列表,如果沒有指定版本,則是最新版本
GET請求:
project (string, required) –專案名
_version (string, optional) –版本號
$ curl http://localhost:6800/listspiders.json?project=myproject
7)、 listjobs.json
獲取指定專案中所有掛起、執行和執行結束的job
GET請求
project (string, option) - restrict results to project name
curl http://localhost:6800/listjobs.json?project=myproject | python -m json.tool
8)、delversion.json
刪除指定專案的指定版本
POST請求
project (string, required) - the project name
version (string, required) - the project version
curl http://localhost:6800/delversion.json -d project=myproject -d version=r99
9)、delproject.json
刪除指定專案,並且包括所有的版本
POST請求
project (string, required) - the project name
curl http://localhost:6800/delproject.json -d project=myproject
未完待續