scrapy框架
Scrapy是用純Python實(shí)現(xiàn)一個(gè)為了爬取網(wǎng)站數(shù)據(jù)刀荒、提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架,用途非常廣泛。
scrapy各部分簡介:
Scrapy Engine(引擎): 負(fù)責(zé)信號和數(shù)據(jù)的傳遞,起協(xié)調(diào)作用.(框架幫我們實(shí)現(xiàn)了)
Scheduler(調(diào)度器): 會(huì)將Request請求任務(wù),存儲(chǔ)在任務(wù)隊(duì)列中曼追,引擎會(huì)從任務(wù)隊(duì)列中提取任務(wù)交給下載器 (框架幫我們實(shí)現(xiàn)了)
只有當(dāng)調(diào)度器中不存在任何request了汉规,整個(gè)程序才會(huì)停止礼殊,(也就是說驹吮,對于下載失敗的URL,Scrapy也會(huì)重新下載晶伦。)
Downloader(下載器):接收引擎?zhèn)鬟f過來的請求碟狞,發(fā)起請求,獲取響應(yīng)婚陪,最終將響應(yīng)結(jié)果交給spider爬蟲文件(框架幫我們實(shí)現(xiàn)了)
Spider(爬蟲):根據(jù)起始url發(fā)起請求族沃,解析響應(yīng)結(jié)果,第一獲取目標(biāo)數(shù)據(jù)泌参,第二提取新的url 〈嘌汀(手動(dòng)實(shí)現(xiàn))
Item Pipeline(管道):將spider爬蟲文件yeild的item數(shù)據(jù),做過濾和持久化 」烈弧(手動(dòng)實(shí)現(xiàn)的)
Downloader Middlewares(下載中間件):自定義下載組件(請求任務(wù)和響應(yīng)結(jié)果都會(huì)經(jīng)過下載中間件)代理中間件盖溺,cookies中間件,Uaer-Agent中間件铣缠,selenium中間件..『嬷觥(特殊需求要手動(dòng)實(shí)現(xiàn))
Spider Middlewares(Spider中間件):可以自定義request請求和過濾Response響應(yīng) (特殊需求要手動(dòng)實(shí)現(xiàn))
安裝
sudo pip3 install scrapy
新建項(xiàng)目
scrapy startproject 爬蟲項(xiàng)目名稱
然后cd到spider文件夾下
新建爬蟲文件
crapy genspider 爬蟲文件名稱 域名:制作爬蟲開始爬取網(wǎng)頁
在這個(gè)時(shí)候我們項(xiàng)目的目錄結(jié)構(gòu)應(yīng)該會(huì)是這樣的
一個(gè)項(xiàng)目有5個(gè)文件我們一般情況下會(huì)進(jìn)行修改
1.pipeline.py
做數(shù)據(jù)的過濾和持久化
可以在這里做數(shù)據(jù)持久化, 如果有多個(gè)管道文件,并且有優(yōu)先級順序一定要記住return item,否則下一個(gè)管道無法接受item
它還要兩個(gè)可選方法
def open_spider(self,spider):
? ? ? ? 可選方法蝗蛙,在爬蟲開始執(zhí)行的時(shí)候調(diào)用一次
? ? ? ? print(spider.name,'爬蟲開啟')
? ? def close_spider(self,spider):
? ? ? ? 可選方法,在爬蟲結(jié)束的時(shí)候調(diào)用一次
? ? ? ? self.file.close()
? ? ? ? print(spider.name,'爬蟲結(jié)束')
2.item.py
根據(jù)目標(biāo)網(wǎng)站蝇庭,定義要提取的目標(biāo)字段
3.spiders.py
spiders文件夾下存放的是爬蟲文件
name
? ? 定義spider名字的字符串。
allowed_domains
? ? 包含了spider允許爬取的域名(domain)的列表歼郭,可選。
start_urls
? ? 初始URL元組/列表辐棒。當(dāng)沒有制定特定的URL時(shí)病曾,spider將從該列表中開始進(jìn)行爬取。
start_requests(self)
? ? 該方法必須返回一個(gè)可迭代對象(iterable)漾根。該對象包含了spider用于爬忍┩俊(默認(rèn)實(shí)現(xiàn)是使用 start_urls 的url)的第一個(gè)Request。
? ? 當(dāng)spider啟動(dòng)爬取并且未指定start_urls時(shí)辐怕,該方法被調(diào)用逼蒙。
parse(self, response)
? ? 當(dāng)請求url返回網(wǎng)頁沒有指定回調(diào)函數(shù)時(shí),默認(rèn)的Request對象回調(diào)函數(shù)寄疏。
yield 的作用就是把一個(gè)函數(shù)變成一個(gè) generator(生成器)是牢,帶有 yield 的函數(shù)不再是一個(gè)普通函數(shù),Python 解釋器會(huì)將其視為一個(gè) generator
4.settings.py
設(shè)置文件,可以在里面做User-Agent陕截,Headers驳棱,激活管道文件等等
BOT_NAME
(也是項(xiàng)目名稱)。使用 startproject 命令創(chuàng)建項(xiàng)目時(shí)會(huì)被自動(dòng)賦值农曲。
SPIDER_MODULES = ['ziruproject.spiders'] NEWSPIDER_MODULE = 'ziruproject.spiders'
爬蟲的文件路徑
USER_AGENT
用戶代理社搅,一般設(shè)置這個(gè)參數(shù)用來偽裝瀏覽器請求
ROBOTSTXT_OBEY
是否遵守ROBOT協(xié)議,為False時(shí),表示不遵守形葬,
為True時(shí)表示遵守(默認(rèn)為True)
COOKIES_ENABLED
是否要攜帶cookies合呐,一般情況下,不是必須要攜帶
cookies的請求笙以,我們將這個(gè)參數(shù)設(shè)置為False淌实,(默認(rèn)為True)
DEFAULT_REQUEST_HEADERS
默認(rèn): 如下
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
用于Scrapy HTTP請求的默認(rèn)標(biāo)頭
ITEM_PIPELINES
設(shè)置并激活管道文件,為了存儲(chǔ)數(shù)據(jù)使用源织,
后面的數(shù)字表示優(yōu)先級翩伪,數(shù)字越小,優(yōu)先級越高
關(guān)于日志信息的設(shè)置
LOG_ENABLED
默認(rèn): True
是否啟用logging谈息。
LOG_FILE
默認(rèn): None
logging輸出的文件名缘屹。如果為None,則使用標(biāo)準(zhǔn)錯(cuò)誤輸出(standard error)侠仇。
Logging使用
Scrapy提供了log功能轻姿,可以通過 logging 模塊使用。
可以修改配置文件settings.py逻炊,任意位置添加下面兩行互亮,效果會(huì)清爽很多。
LOG_FILE = "TencentSpider.log"
LOG_LEVEL = "INFO"
5.middleware.py
下載中間件和爬蟲中間件
middleware的使用主要是為了自定義一些第三方組件余素,是爬蟲和反爬的重要過程
主要有四種:
1.隨機(jī)User-Agent
2.自定義隨機(jī)cookies
3.enium結(jié)合使用
4.自定義隨機(jī)ip池
除了一般的scrapy框架之外還有通用爬蟲
通用爬蟲和一般爬蟲的區(qū)別主要是多了一個(gè)Rule的規(guī)則
他的主要參數(shù)是:
LinkExtractor中有:
allow:一般設(shè)置一個(gè)正則表達(dá)式豹休,符合該正則表達(dá)式的連接,提取該url(常用)
deny:同樣是跟一個(gè)正則表達(dá)式桨吊,符合該正則表達(dá)式的連接威根,不提取該url
(優(yōu)先級比allow要高)
?allowed_domains:提取的連接,必須在allowed_domains設(shè)置的域下
? deny_domains: 提取鏈接時(shí)视乐,一定不能提取deny_domains設(shè)置的域下
restrict_xpaths:當(dāng)提取鏈接的時(shí)候洛搀,我們可以使用xpath語法定位到某些標(biāo)簽,提取標(biāo)簽下佑淀,
?符合規(guī)則的鏈接×裘馈(常用)
tags:可以指定要提取哪些標(biāo)簽
?attrs:可以指定要提取標(biāo)簽的哪些屬性
?restrict_css:當(dāng)提取鏈接的時(shí)候,我們可以使用css語法定位到某些標(biāo)簽伸刃,提取標(biāo)簽下谎砾,
?符合規(guī)則的鏈接 (常用)
還有:
callback='回調(diào)函數(shù)名稱',
?follow=True | False,? # 表示是否要跟進(jìn)
爬蟲的步驟
step1:
分析目標(biāo)網(wǎng)站,根據(jù)要提取的目標(biāo)數(shù)據(jù)捧颅,在items.py中自定義字段
step2:
? ? 在爬蟲文件中:(1)首先設(shè)置目標(biāo)url
? ? ? ? ? ? ? ? ????????????????(2) 解析請求成功的響應(yīng)結(jié)果,提取目標(biāo)數(shù)據(jù)棺榔,賦值給item,提取新的url,繼續(xù)發(fā)起請求
step3:
? ? (1) 在設(shè)置文件中激活管道
? ? (2) 在管道文件中做數(shù)據(jù)的過濾和持久化
注意:
1.進(jìn)入項(xiàng)目一定要先設(shè)置虛擬環(huán)境
2.首先更改settings的幾個(gè)配置
? ? (1).ROBOTSTXT_OBEY
是否遵守ROBOT協(xié)議隘道,為False時(shí)症歇,表示不遵守郎笆,
為True時(shí)表示遵守(默認(rèn)為True)
(2).COOKIES_ENABLED
是否要攜帶cookies,一般情況下忘晤,不是必須要攜帶
cookies的請求宛蚓,我們將這個(gè)參數(shù)設(shè)置為False,(默認(rèn)為True)
(3).DEFAULT_REQUEST_HEADERS
此設(shè)置是設(shè)置一個(gè)全局的請求頭
默認(rèn): 如下
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
(4).DOWNLOAD_DELAY =1(防止訪問過于頻繁)
表示延時(shí)下載设塔,一般情況下設(shè)為1或2
通用爬蟲:為了全站爬取
通用爬蟲創(chuàng)建項(xiàng)目
scrapy genspider -t crawl 爬蟲名稱 域
通用爬蟲與普通爬蟲的區(qū)別就在于多了一個(gè)rules規(guī)則
rules 規(guī)則屬性的參數(shù):是一個(gè)元組,可以放多個(gè)Rule對象
創(chuàng)建Rule:
LinkExtractor:設(shè)置提取規(guī)則
(allow,deny,allow_domea..,deny_domea..,restrict_xpath,restrict_css)
callback:設(shè)置回調(diào)函數(shù)
follwer:是否跟進(jìn)
process_links:設(shè)置一個(gè)函數(shù),根據(jù)正則規(guī)則獲取的url,可以在回調(diào)函數(shù)中獲取到
processs_request:設(shè)置一個(gè)函數(shù),可以在這個(gè)回調(diào)方法中攔截所有根據(jù)正則規(guī)則提取到的url構(gòu)建的Request對象
注意:
1.設(shè)置回調(diào)的時(shí)候一定不能重寫parse方法
2.要獲取起始url的響應(yīng)結(jié)果 ,必須重寫parse_start_url
3.在設(shè)置Rule對象的時(shí)候,如果沒有callback回調(diào)函數(shù),默認(rèn)表示跟進(jìn)
什么情況下會(huì)用到通用爬蟲???
當(dāng)我們提取數(shù)據(jù)的目標(biāo)網(wǎng)站的網(wǎng)址很有規(guī)律,并且模塊很清晰,我么就可以使用通用爬蟲class
數(shù)據(jù)持久化之圖片下載
在 ImagesPipeline 類中實(shí)現(xiàn)凄吏,提供了一個(gè)方便并具有額外特性的方法,來下載并本地存儲(chǔ)圖片
首先在setttings里設(shè)置一個(gè)圖片下載路徑
然后在自定義的圖片下載管道里獲取到這個(gè)圖片路徑
第一種:正常的發(fā)起請求 闰蛔,獲取圖片的二進(jìn)制文件痕钢,保存
第二種:自定義圖片管道,繼承自ImagePipline
? ? 重寫兩個(gè)方法:
? ? ? ? def get_media_request(self,item,spider):
? ? ? ? ? ? 獲取圖片地址序六,發(fā)起請求
? ? ? ? def item_completed(self,results,spider,item,....):
? ? ? ? ? ? 在results結(jié)果中根據(jù)圖片下載狀態(tài)任连,獲取圖片本地存儲(chǔ)的路徑,
? ? ? ? ? ? 將獲取的路徑賦值給item,然后將item返回給其他管道
# 數(shù)據(jù)持久化:(切記激活管道)
? ? 1.可以自定義數(shù)據(jù)管道
? ? ? ? def __init__(self,xxx,xxxxx,xxxxx):
? ? ? ? ? ? # 可以設(shè)置一些參數(shù)例诀,(比如随抠,創(chuàng)健數(shù)據(jù)庫鏈接,打開文件等等
? ? ? ? @classmethod
? ? ? ? def from_crawler(cls,crawler):
? ? ? ? ? ? crawler:包含了爬蟲的一些核心組件繁涂,可以獲取settings中的一些參數(shù)
? ? ? ? ? ? return cls(xxx,xxxx,xxxx)
? ? ? ? def open_spider(self,spider):
? ? ? ? ? ? # 可選方法拱她,在爬蟲個(gè)開啟的時(shí)候會(huì)調(diào)用
? ? ? ? def process_item(self,item,spider):
? ? ? ? ? ? # 所有的item都會(huì)經(jīng)過這個(gè)方法
? ? ? ? ? ? # 在這里做數(shù)據(jù)持久化(pymongo,pymysql)
? ? ? ? ? ? # 方法一:
? ? ? ? ? ? if isinstance(item,類名)
? ? ? ? ? ? ? ? 做數(shù)據(jù)插入操作
? ? ? ? ? ? elif isinstance(item,類名)
? ? ? ? ? ? ? ? 做數(shù)據(jù)插入操作
? ? ? ? ? ? 方法二:
? ? ? ? ? ? ? ? 1.在item對應(yīng)的類中,我們定義一個(gè)方法扔罪,返回sql語句和要插入的數(shù)據(jù)
? ? ? ? ? ? ? ? 2.使用item調(diào)用這個(gè)方法秉沼,得到sql語句和要插入的數(shù)據(jù)
? ? ? ? ? ? ? ? 3.執(zhí)行插入操作
? ? ? ? ? ? return item(如果要將item,傳遞給下一個(gè)管道,必須要return)
數(shù)據(jù)持久化之mongodb
首先在settings設(shè)置數(shù)據(jù)庫配置文件
MONGDDBHOST = '127.0.0.1'
MONGODBPORT = 27017
MONGODB_DB = 'dbname'
import pymongo
class QunaPipeline(object):
? ? def __init__(self,MONGODBHOST,MONGODBPORT,MONGODB_DB):
? ? ? ? self.client = pymongo.MongoClient(MONGODBHOST,MONGODBPORT)
? ? ? ? self.db = self.client[MONGODB_DB]
? ? @classmethod
? ? def from_settings(cls,settings):
? ? ? ? MONGODBHOST = settings['MONGODBHOST']
? ? ? ? MONGODBPORT = settings['MONGODBPORT']
? ? ? ? MONGODB_DB = settings['MONGODB_DB']
? ? ? ? return cls(MONGODBHOST,MONGODBPORT,MONGODB_DB)
? ? def process_item(self, item, spider):
? ? ? ? self.db[item.get_db_col()].insert(dict(item))
? ? ? ? return item
數(shù)據(jù)持久化之mysql
同樣的矿酵,我們也把數(shù)據(jù)庫的配置信息唬复,寫在settings里
MYSQL_HOST = 'localhost'
MYSQL_USER = 'root'
MYSQL_PWD = 'pwd'
MYSQL_DB = 'dhname'
import pymysql
from jobboleproject.items import JobboleprojectItem
class JobboleprojectPipeline(object):
? ? def __init__(self,host,user,pwd,db):
? ? ? ? #創(chuàng)建mysql連接
? ? ? ? self.client = pymysql.Connect(host,user,pwd,db,charset='utf8')
? ? ? ? #創(chuàng)建游標(biāo)
? ? ? ? self.cursor = self.client.cursor()
? ? @classmethod
? ? def from_crawler(cls, crawler):
? ? ? ? host = crawler.settings['MYSQL_HOST']
? ? ? ? user = crawler.settings['MYSQL_USER']
? ? ? ? pwd = crawler.settings['MYSQL_PWD']
? ? ? ? db = crawler.settings['MYSQL_DB']
? ? ? ? return cls(host,user,pwd,db)
? ? def process_item(self,item,spider):
? ? ? ? data = dict(item)
? ? ? ? sql,parmars = item.insert_db_by_data(data)
? ? ? ? try:
? ? ? ? ? ? self.cursor.execute(sql,parmars)
? ? ? ? ? ? self.client.commit()
? ? ? ? except Exception as err:
? ? ? ? ? ? self.client.rollback()
? ? ? ? ? ? print(err)
? ? ? ? return item
? ? def close_spider(self,spider):
? ? ? ? self.cursor.close()
? ? ? ? self.client.close()
Scrapy Shell
scrapy還有一個(gè)交互終端,我們可以在未啟動(dòng)spider的情況下嘗試及調(diào)試代碼坏瘩,也可以用來測試XPath或CSS表達(dá)式盅抚,查看他們的工作方式漠魏,方便我們爬取的網(wǎng)頁中提取的數(shù)據(jù)倔矾。
啟動(dòng)
scrapy shell? 爬取目標(biāo)網(wǎng)頁
electors選擇器?Scrapy Selectors 內(nèi)置 XPath 和 CSS Selector 表達(dá)式機(jī)制?Selector有四個(gè)基本的方法,最常用的還是xpath:
xpath(): 傳入xpath表達(dá)式柱锹,返回該表達(dá)式所對應(yīng)的所有節(jié)點(diǎn)的selector list列表
extract(): 序列化該節(jié)點(diǎn)為字符串并返回list
css(): 傳入CSS表達(dá)式哪自,返回該表達(dá)式所對應(yīng)的所有節(jié)點(diǎn)的selector list列表,語法同 BeautifulSoup4
re(): 根據(jù)傳入的正則表達(dá)式對數(shù)據(jù)進(jìn)行提取禁熏,返回字符串list列表
scrapy -h 查看所有可用的命令:
scrapy view -h 查看view命令的詳細(xì)內(nèi)容:
scrapy list列出當(dāng)前項(xiàng)目中所有可用的spider
scrapy runspider xxxx.py在未創(chuàng)建項(xiàng)目的情況下壤巷,運(yùn)行一個(gè)編寫在Python文件中的spider。
scrapy version輸出Scrapy版本
Scrapy 的暫停和恢復(fù)
爬取大的站點(diǎn)瞧毙,我們希望能暫停爬取胧华,之后再恢復(fù)運(yùn)行寄症。
scrapy crawl 爬蟲名稱 -s JOBDIR=crawls/爬蟲名稱
如要暫停,直接Ctrl+C即可矩动,若要恢復(fù)有巧,再一次運(yùn)行此代碼即可