文章目錄
如何安裝創建啓動項目等基礎操作我在之前的一篇博客中已經完整的介紹過了,如果你還不會上述操作可以查看我上篇博客爬蟲框架(Scrapy)簡介(https://xunmi.blog.csdn.net/article/details/105408249)
Scrapy的爬蟲流程
從上圖可以看出,使用Scrapy的一個大致流程,
- 指定第一個URL放入調度器
- 下載器會從調取器中讀取URL並自動訪問下載,傳入爬蟲
- 爬蟲將提取的URL在此傳入調度器,提取的數據傳入管道進行保存
- 重複上述操作,直到完成調度器中所有的URL
本片博客主要介紹Spider部分和Irem部分
spiders(爬蟲包)
創建項目
我們創建項目後就能在項目文件夾中看見一個自動創建的spiders文件夾,而這個文件夾中默認有一個__init__.py
文件,也就是此文件夾被定義爲一個包,這個包就是用來存放我們的爬蟲文件的。
我們在命令行中執行scrapy genspider 爬蟲名 "運行爬取的域名"
命令即可生成一個爬蟲文件
此命令會根據爬取的域名自動生成一個允許的域(allowed_domains)和開始爬取的URL(start_urls)。
下面我使用陽光問政平臺作爲我們的測試項目進行爬取
陽光問政(wz.sun0769.com)
創建爬蟲的時候http或https協議建議不帶(因爲wz.sun0769.com的範圍比http://wz.sun0769.com更大,不過這個帶不帶在大部分網站中都沒有影響)
scrapy genspider 陽光問政 "wz.sun0769.com"
創建項目後,自動生成的開始URL可能並不是我們真正開始爬取的URL,這裏我們可以手動修改一下,比如說我這裏想爬取陽光問政的最新問政頁面(http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1)
class A陽光問政Spider(scrapy.Spider):
name = '陽光問政'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1']
response方法
創建的爬蟲中帶一個def parse(self, response):
方法,從上圖中我們可以看出,調度器會自動將我們首個url(start_urls)傳入下載器,並下載其內容,而首個URL中的下載內容這會傳入parse方法中的response屬性中,也就是我們調用此屬性即可實現首個頁面的內容讀取。
如果想看response的源碼可以在from scrapy.http.response import Response
中查看
response方法 | 作用 |
---|---|
.xpath() |
篩選規則,不會用xpath的點擊這裏, 非常常用 |
.css() |
篩選規則 |
.text |
直接獲取相應(response)文本 |
.copy() |
輸出此相應(response)的副本 |
.replace() |
根據給定值創建一個新的相應(response),給定的值可以爲’url’, ‘status’, ‘headers’, ‘body’, ‘request’, ‘flags’, ‘certificate’ |
.urljoin(url) |
將此相應的url與給定的url連接起來。 |
.follow() |
像調度器中存放URL,在此需要請求的網站,相當於scrapy.Request() 。非常重要,下面會着重介紹scrapy.Request() 的作用 |
.follow_all() |
像調度器中放入多個URL,源碼層面上就是多次調用.follow() |
我們在parse方法中對首個URL的相應(response)可以直接使用xpath提取數據
def parse(self, response):
tr_data = response.xpath('//div[@class="width-12"]/ul[@class="title-state-ul"]/li/span[3]/a')
for tr in tr_data:
data['標題'] = tr.xpath('./text()').extract_first()
data['詳情URL'] = tr.xpath('./@href').extract_first()
data['詳情URL'] = "http://wz.sun0769.com" + data['詳情URL']
print(data)
當前一個簡單的頁面爬取就已經完成了。
response.follow()與scrapy.Request()方法
.follow()
是scrapy在較新的版本中推出的方法,相比於scrapy.Request()
,我跟推薦大家使用response.follow()
對於初學者來說這兩個方法效果是相同的,他們接收的屬性,和執行的效果都完全一樣,不太相同的是response.follow()
方法接受的URL可以是相對URL或“scrapy.link.link”對象。
上述的爬取中,我還獲取了詳情URL的地址,那麼我如何將詳情URL傳入調度器,這裏就要用到.follow()
了。我們先看一下.follow()中常用的有哪些屬性。
.follow() 常用屬性 |
作用 |
---|---|
url |
必填,像調度器中傳入的新URL |
callback=None |
滿足此條件的url回調的函數(默認: 空) |
method=GET |
請求時使用的方法(默認:GET) |
headers=None |
請求頭 |
cookies=None |
請求攜帶的cookies |
meta=None |
此屬性一般用來傳遞變量(在一個方法中提取的數據傳遞進入另一個方法使用,必須已字典的形式傳入) |
encoding='utf-8' |
請求時的字符編碼 |
需要注意的是,在scrapy中我們結束一個方法用的大多數都是yield
讓其變成一個生成器,而不是return
直接結束這個方法。
下面我們就來爬取一下 陽光問政 這個網站的所有最新問政
# -*- coding: utf-8 -*-
import scrapy
from scrapy.http.response import Response
class A陽光問政Spider(scrapy.Spider):
name = '陽光問政'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1']
def parse(self, response):
tr_data = response.xpath('//div[@class="width-12"]/ul[@class="title-state-ul"]/li/span[3]/a')
for tr in tr_data:
data = {}
data['標題'] = tr.xpath('./text()').extract_first()
data['詳情URL'] = tr.xpath('./@href').extract_first()
data['詳情URL'] = "http://wz.sun0769.com" + data['詳情URL']
yield response.follow(
url=data['詳情URL'],
callback=self.details_parse,
meta={'data': data}
)
next_url ="http://wz.sun0769.com" + response.xpath('//div[@class="width-12"]/div[3]/a[2]/@href').extract_first()
yield response.follow(
url=next_url,
callback=self.parse
)
def details_parse(self, response):
data = response.meta.get('data')
data['內容'] = response.xpath('//div[@class="details-box"]/pre/text()').extract()
img = response.xpath('//div[@class="mr-three"]/div[3]/img/@src').extract()
if img:
data['配圖'] = img
print(data)
items.py(項目)
除了爬蟲外items.py是用來規範提取的數據的一個文件,他用於指定提取數據的鍵名。
打開items.py後我們會發現裏面有個一個繼承與scrapy.Item
的類,其中包含鍵名 = scrapy.Field()
這樣一個屬性,這個數據就是用於定義鍵名的。
首先我們可以創建一些鍵名.然後在爬蟲中可以進行引用並賦值給我們創建用於存儲網站數據的變量。這時候我們的變量必須使用items.py中定義過的鍵名,否則會出現報錯。
items.py的存在使項目變得規範,而非強制使用。
pipelines(管道)
管道用於進行數據處理,我們在爬蟲(spiders)中已經將需要的數據提取出來了,但提取出來的數據如何存儲,存儲爲什麼格式,存儲在哪個地方,這都是在管道中進行的。使用管道前,我們需要先在設置(setting.py)中啓動管道。
啓動管道
打開設置(setting.py)後我們需要先將一下代碼的註釋刪除
ITEM_PIPELINES = {
'scrapy_text.pipelines.ScrapyTextPipeline': 300,
}
其中ScrapyTextPipeline
是管道(pipelines.py)中的的類名,這裏可以同時存在多個管道,而後面的數字着表示爲優先級,數字越小,優先級越高,數據會優先傳入優先級高的管道
使用管道
配置好後,我們爲了驗證是否能將數據傳入管道,我們可以直接將提取的數據進行輸出(print()),
打開管道設置後,我們只需在爬蟲中將數據使用yield方法傳入即可,管道的item變量會自動接收爬蟲傳出的數據。
保存數據這裏就不細講了,之後我會專門寫一篇如何將scrapy爬取的數據保存進入數據庫的博客。
常用設置(settings.py)
我想將我漢化註釋後的設置放出來,其中原設置沒有的屬性只有LOG_LEVEL = 'WARNING'
,這個設置是用來設置輸出的log的等級的,如果不這麼設置,我們輸出的時候會攜帶一大堆當前爬蟲的配置信息,這裏大多數信息對我們來說都是沒有太大用處的,所以我這裏設置了只有出現警告(WARNING)及以上的信息纔會輸出。
# -*- coding: utf-8 -*-
# Scrapy 的 scrapy_text 項目的設置
#
# 爲簡單起見,此文件僅包含被認爲重要或常用的設置。您可以在參考文檔中找到更多設置:
#
# https://docs.scrapy.org/en/latest/topics/settings.html
# https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'scrapy_text'
SPIDER_MODULES = ['scrapy_text.spiders']
NEWSPIDER_MODULE = 'scrapy_text.spiders'
# 命令行出入的log等級,(默認爲全部輸出)
LOG_LEVEL = 'WARNING'
# 通過在用戶代理上標識您自己(和您的網站)負責任地爬行
#USER_AGENT = 'scrapy_text (+http://www.yourdomain.com)'
# 當前是否遵循爬蟲協議
ROBOTSTXT_OBEY = False
# 配置Scrapy執行的最大併發請求數(默認值:16)
#CONCURRENT_REQUESTS = 32
# 爲同一網站的請求配置延遲(默認值:0)
# 見 https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# 參見 autothrottle 設置和文檔
#DOWNLOAD_DELAY = 3
# 下載延遲設置將僅支持以下選項之一:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# 禁用Cookie(默認情況下已啓用)
#COOKIES_ENABLED = False
# 禁用Telnet控制檯(默認啓用)
#TELNETCONSOLE_ENABLED = False
# 重寫默認請求頭:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# 啓用或禁用爬蟲中間件(middleware)
# 見 https://docs.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'scrapy_text.middlewares.ScrapyTextSpiderMiddleware': 543,
#}
# 啓用或禁用下載器中間件(middleware)
# 見 https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'scrapy_text.middlewares.ScrapyTextDownloaderMiddleware': 543,
#}
# 啓用或禁用擴展
# 見 https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# 配置項管道(pipelines)
# 見 https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'scrapy_text.pipelines.ScrapyTextPipeline': 300,
}
# 啓用和配置自動限速(AutoThrottle)擴展(默認禁用) 此選項配置根據網站負載進行自動限速
# 看 https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# 初始下載延遲
#AUTOTHROTTLE_START_DELAY = 5
# 在高延遲情況下設置的最大下載延遲
#AUTOTHROTTLE_MAX_DELAY = 60
# Scrapy應該並行發送的請求的平均數量
# 每個遠程服務器
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# 啓用顯示節流的每一個響應收到的統計:
#AUTOTHROTTLE_DEBUG = False
# 啓用和配置HTTP緩存(默認禁用)
# 看 https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
調用自定義設置
上述的設置都是scrapy自帶的,除此之外設置的主要作用是存放一些公共的變量(比如數據庫的地址,賬號密碼等),方便自己和別人修改。需要注意的是,設置中的變量名都是大寫的(並非強制,但是一種規範)。
假設我們當前在設置中存儲了數據庫的地址,我們如何去調用它呢。
大部分人最先想到的方法可能都是引用該文件
from scrapy_text.settings import SQL_HOST
,然後調用即可
上述方法雖然沒錯,達成了我們想要的目的,但其實scrapy給我們提供了更加便利的方法已供我們使用。在爬蟲中self.settings.get('SQL_HOST')
就能提取出我們設置中的內容,無需引入設置。self.settings
會已字典的形式將設置文件讀取出來。
在管道中,我們需要讀取配置文件就需要用到管道中攜帶的spider
屬性,而非self了,
spider.settings.get('SQL_HOST')