現在說到爬蟲,大家都會或多或少地將 python 和爬蟲聯繫在一起,歸根到底,是因為 python 豐富的生態和靈活簡單的語法。同時基於 python 存在有幾個強大的爬蟲框架,極大地降低了爬蟲的難度,提高了編寫程序的效率。最近我也體驗了一下 scrapy,算是做一個入門的記錄吧
簡介#
Scrapy 是一個用於爬網網站和提取結構化數據的應用程序框架,可用於各種有用的應用程序,例如數據挖掘,信息處理或歷史檔案。
—— 翻譯自官網
推薦直接查看官網,裡面甚至有完整的 scrapy 教程,簡直是深入學習框架的必備選擇!
安裝#
在安裝 scrapy 框架的時候,網上有許多方法,針對 python 的環境不同,可能存在奇奇怪怪的錯誤,這裡我基於 python3 環境,預裝了 pip,親測一遍過
預裝環境
Windows 10 + python 3.7.0 + pip20.1 +virtualenv
同時請開啟一個新的 virtual 環境來保證不會出現其他包的依賴衝突
前期安裝組件
lxml
pyOpenSSL
Twisted
PyWin32
安裝 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
發起請求給Engine
Engine
安排請求Scheduler
和接受下一個爬取請求Scheduler
返回下一個請求Engine
將請求通過Downloader Middlewares
發送給Downloader
Downloader
爬取網頁並將返回結果通過Downloader Middlewares
發送回Engine
- 引擎接受響應並通過
Spider Middleware
轉發給Spider
處理 Spider
的parse()
方法對獲取到的response
進行處理,解析出items
或者請求,將解析出來的items
或請求,返回給Engine
Engine
將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
文件