現在說到爬蟲,大家都會或多或少地將 python 和爬蟲聯繫在一起,歸根到底,是因為 python 豐富的生態和靈活簡單的語法。同時基於 python 存在有幾個強大的爬蟲框架,極大地降低了爬蟲的難度,提高了編寫程序的效率。最近我也體驗了一下 scrapy,算是做一個入門的記錄吧
簡介#
Scrapy 是一個用於爬網網站和提取結構化數據的應用程序框架,可用於各種有用的應用程序,例如數據挖掘,信息處理或歷史檔案。
—— 翻譯自官網
推薦直接查看官網,裡面甚至有完整的 scrapy 教程,簡直是深入學習框架的必備選擇!
安裝#
在安裝 scrapy 框架的時候,網上有許多方法,針對 python 的環境不同,可能存在奇奇怪怪的錯誤,這裡我基於 python3 環境,預裝了 pip,親測一遍過
預裝環境
Windows 10 + python 3.7.0 + pip20.1 +virtualenv
同時請開啟一個新的 virtual 環境來保證不會出現其他包的依賴衝突
前期安裝組件
lxmlpyOpenSSLTwistedPyWin32
安裝 lxml
直接pip安裝即可。這是python一個HTML、XML解析庫,即使不用框架也是經常使用的
pip3 install lxml
安裝 PyWin32
官网下载对应版本的安装包双击安装即可 [pywin32]([https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/](https://sourceforge.net/projects/pywin32/files/pywin32/Build 221/))
安裝剩餘組件
這裡首先要介紹wheel
wheel是python的一個打包格式,以前python主流的打包格式是.egg文件,但現在*.whl文件也變得流行起來。
wheel其實上是 python 上一種壓縮打包的組件,有點類似於 zip 之類的,但在本文中你只要知道通過 wheel 文件格式文件你可以快速將一個庫安裝到你的python環境中
安裝其實也很簡單
pip3 install wheel
這樣你的python環境就支持.whl文件格式的安裝啦
接下來的步驟就是到各個官網上下載各組件的whl格式,注意要和你的 python 環境匹配
安裝
pip3 install pyOpenSSL-19.1.0-py2.py3-none-any.whl
Twisted注意要和你的 python 版本對應
像我的環境就是
pip3 install Twisted-20.3.0-cp37-cp37m-win_amd64.whl
安裝 scrapy
所有依賴包安裝成功後直接 pip 安裝 scrapy 就不會有問題啦
pip3 install Scrapy
組件介紹#
首先創建項目
在你想要放置爬蟲項目的文件夾運行,xxx 就是你的項目名
scrapy startproject xxx
順便記錄一下一些基本的操作
- 創建項目:
scrapy startproject xxx - 進入項目:
cd xxx #進入某個文件夾下 - 創建爬蟲:
scrapy genspider xxx(爬蟲名) xxx.com (爬取域) - 生成文件:
scrapy crawl xxx -o xxx.json (生成某種類型的文件) - 運行爬蟲:
scrapy crawl XXX - 列出所有爬蟲:
scrapy list - 獲得配置信息:
scrapy settings [options]
創建完成後你可以看到文件夾下多了這些內容
讓我們一個個介紹這些組件(spider_demo是你的爬蟲項目名)
scrapy.cfg: 項目的配置文件 (在項目文件夾的平行目錄下)spider_demo/spiders/: 放置spider代碼的目錄. (放爬蟲的地方)也是你放爬蟲具體邏輯的地方spider_demo/items.py: 項目中的item文件.(創建容器的地方,也是定義最終爬蟲得到的結果格式的地方)spider_demo/pipelines.py: 項目中的pipelines文件.(實現數據的清洗、存儲和驗證)spider_demo/settings.py: 項目的設置文件.(爬蟲的具體配置,包括啟動某個中間件,啟動關閉某個功能等)spider_demo/middlewares.py: 定義項目的下載器中間件和爬蟲中間件
感覺是不是還有點蒙圈?接下來簡單介紹一下scrapy運行的原理,這樣相信就能更理解這些組件的作用了
官網的流程圖

Scrapy是由執行引擎控制執行的
Spider發起請求給EngineEngine安排請求Scheduler和接受下一個爬取請求Scheduler返回下一個請求Engine將請求通過Downloader Middlewares發送給DownloaderDownloader爬取網頁並將返回結果通過Downloader Middlewares發送回Engine- 引擎接受響應並通過
Spider Middleware轉發給Spider處理 Spider的parse()方法對獲取到的response進行處理,解析出items或者請求,將解析出來的items或請求,返回給EngineEngine將items發送到Item Pipline, 將請求發送到Scheduler- 重複步驟 1 直到沒有新的請求
總結一下上面步驟出現的組件
| 组件名 | 组件功能 | |
|---|---|---|
| Engine | 框架核心,負責整體的數據和信號的調度 | 框架實現 |
| Scheduler | 一個存放請求的隊列 | 框架實現 |
| Downloader | 執行具體下載任務的單元 | 框架實現 |
| Spider | 處理下載得到的響應結果,提取需要的是數據(具體的業務邏輯) | 自己實現 |
| Item Pipline | 處理最終得到的數據,如進行持久化操作 | 自己實現 |
| Downloader MIddlewares | 在正式進行下載任務之前,可以進行一些自定義處理。比如設置請求頭,設置代理 | 自己實現 |
| Spider Midderwares | 自定義請求和過濾響應 | 自己實現 |
相信這一套組合拳下來應該能對這個框架有了基本的認識,接下來就通過實戰來強化一下記憶吧
簡單應用#
這次是根據網上通過爬取貓眼電影的排行榜做的一個demo,以後有時間再換一個更加複雜的demo
實現目標是爬取電影排行榜上的片名、分數和排名,同時將結果以json的格式保存在一個.json文件中

首先你要確定你需要爬取哪些數據,將你需要的數據記錄到容器中,在item.py中進行編寫:
import scrapy
#這裡我們需要排名、標題、收藏人數、上映時間和分數
class SpiderDemoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
index = scrapy.Field()
title = scrapy.Field()
star = scrapy.Field()
releasetime = scrapy.Field()
score = scrapy.Field()
接下來在Spiders文件夾下新建一個爬蟲文件,例如我新建了一個MoyanSpider.py文件
import scrapy
from spider_demo.items import SpiderDemoItem
class MaoyanSpider(scrapy.Spider):
#這是爬蟲啟動的名稱,之後啟動爬蟲就需要用到這個名稱
name = "maoyan"
#可以爬取的域名可選列表
allowed_domains = ["maoyan.com"]
#目標爬取的網址
start_urls = [
"http://maoyan.com/board/7/",
"http://maoyan.com/board/4/",
]
#處理已經下載的頁面
def parse(self, response):
dl = response.css(".board-wrapper dd")
#通過解析得到具體的數據存到容器中
for dd in dl:
item = SpiderDemoItem()
item["index"] = dd.css(".board-index::text").extract_first()
item["title"] = dd.css(".name a::text").extract_first()
item["star"] = dd.css(".star::text").extract_first()
item["releasetime"] = dd.css(".releasetime::text").extract_first()
score = dd.css('.integer::text').extract_first()
if score is not None:
item["score"] = score + dd.css('.fraction::text').extract_first()
else:
item["score"] = 0
#通過yield將結果返回
yield item
這裡提一下,scrapy支持各種類型的解析,你可以使用 python 常見的三大解析庫進行解析,但框架也提供了一種自己的解析方式(Selector)
- 選擇器
Xpath
這裡不詳細敘述,以後有時間再細聊
同時我們需要在setting,py中對配置稍微進行修改 (setting.py中有許多默認配置,這裡只展示修改的部分)
#如果沒有自動生成UA,就需要手動定義,但是每次爬取都是同樣的UA容易出現驗證操作,因此後面還會介紹一種隨機生成UA的方法
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
#允許機器人協議,關於機器人協議的具體內容可以自行上網查找
ROBOTSTXT_OBEY = False
這樣,基本就完成了一個簡單的爬蟲,只需要執行scrapy crawl maoyan(最後一個是你的爬蟲名)

之後還有兩個要點,一個是項目的持久化,一個是隨機化User-Agent。
先看持久化,這裡簡單起見就示範將爬蟲數據以json格式導出
這裡需要修改pipline.py,至於為什麼,相信看了之前的組件介紹應該能明白
import json
import codecs
class SpiderDemoPipeline:
def process_item(self, item, spider):
return item
class JsonPipline(object):
def __init__(self):
print("打開文件,準備寫入....")
self.file = codecs.open("maoyan.json", "wb", encoding='utf-8')
def process_item(self, item, spider):
print("準備寫入...")
line = json.dumps(dict(item), ensure_ascii=False) + "\n"
self.file.write(line)
return item
def close_spider(self, spider):
print("寫入完畢,關閉文件")
self.file.close
然後在setting.py中開啟自定義的pipline
ITEM_PIPELINES = {
# 'spider_demo.pipelines.SpiderDemoPipeline': 300,
'spider_demo.pipelines.JsonPipline': 200
}
至於隨機化 UA,先說明添加 UA 的原理
scrapy首先會讀取setting.py裡面關於 UA 的設置,然後經過middleware,如果沒有進行自定義操作,就會將配置中的 UA 添加到請求頭中。因此,想要實現隨機化 UA, 實際上就可以在發起網頁請求之前,在Download Middleware上做文章。
這裡在middleware.py上做了修改,引入了第三方包fake_useragent
from scrapy import signals
import random
from fake_useragent import UserAgent
class RandomUserAgentMiddleware(object):
# 隨機更換user-agent
def __init__(self, crawler):
super(RandomUserAgentMiddleware, self).__init__()
self.ua = UserAgent()
self.ua_type = crawler.settings.get("RANDOM_UA_TYPE", "random")
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def process_request(self, request, spider):
def get_ua():
return getattr(self.ua, self.ua_type)
request.headers.setdefault('User-Agent', get_ua())
同時在setting.py上做修改
DOWNLOADER_MIDDLEWARES = {
'spider_demo.middlewares.SpiderDemoDownloaderMiddleware': 543,
'spider_demo.middlewares.RandomUserAgentMiddleware': 400,
'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
}
# 隨機選擇UA
#這個是自己設置的,依賴於fake-useragent
RANDOM_UA_TYPE = 'random'
至此,一個簡單的爬蟲應用就實現了!
可以看見UA發生了變化

同時生成了一個maoyan.json文件
