scrapy框架
Scrapy是用純Python實現一個為了爬取網站數據、提取結構性數據而編寫的應用框架,用途非常廣泛。
scrapy各部分簡介:
Scrapy Engine(引擎): 負責信號和數據的傳遞,起協調作用.(框架幫我們實現了)
Scheduler(調度器): 會將Request請求任務,存儲在任務隊列中,引擎會從任務隊列中提取任務交給下載器 (框架幫我們實現了)
只有當調度器中不存在任何request了,整個程序才會停止,(也就是說,對于下載失敗的URL,Scrapy也會重新下載。)
Downloader(下載器):接收引擎傳遞過來的請求,發起請求,獲取響應,最終將響應結果交給spider爬蟲文件(框架幫我們實現了)
Spider(爬蟲):根據起始url發起請求,解析響應結果,第一獲取目標數據,第二提取新的url (手動實現)
Item Pipeline(管道):將spider爬蟲文件yeild的item數據,做過濾和持久化 (手動實現的)
Downloader Middlewares(下載中間件):自定義下載組件(請求任務和響應結果都會經過下載中間件)代理中間件,cookies中間件,Uaer-Agent中間件,selenium中間件.. (特殊需求要手動實現)
Spider Middlewares(Spider中間件):可以自定義request請求和過濾Response響應 (特殊需求要手動實現)
安裝
sudo pip3 install scrapy
新建項目
scrapy startproject 爬蟲項目名稱
然后cd到spider文件夾下
新建爬蟲文件
crapy genspider 爬蟲文件名稱 域名:制作爬蟲開始爬取網頁
在這個時候我們項目的目錄結構應該會是這樣的
一個項目有5個文件我們一般情況下會進行修改
1.pipeline.py
做數據的過濾和持久化
可以在這里做數據持久化, 如果有多個管道文件,并且有優先級順序一定要記住return item,否則下一個管道無法接受item
它還要兩個可選方法
def open_spider(self,spider):
? ? ? ? 可選方法,在爬蟲開始執行的時候調用一次
? ? ? ? print(spider.name,'爬蟲開啟')
? ? def close_spider(self,spider):
? ? ? ? 可選方法,在爬蟲結束的時候調用一次
? ? ? ? self.file.close()
? ? ? ? print(spider.name,'爬蟲結束')
2.item.py
根據目標網站,定義要提取的目標字段
3.spiders.py
spiders文件夾下存放的是爬蟲文件
name
? ? 定義spider名字的字符串。
allowed_domains
? ? 包含了spider允許爬取的域名(domain)的列表,可選。
start_urls
? ? 初始URL元組/列表。當沒有制定特定的URL時,spider將從該列表中開始進行爬取。
start_requests(self)
? ? 該方法必須返回一個可迭代對象(iterable)。該對象包含了spider用于爬取(默認實現是使用 start_urls 的url)的第一個Request。
? ? 當spider啟動爬取并且未指定start_urls時,該方法被調用。
parse(self, response)
? ? 當請求url返回網頁沒有指定回調函數時,默認的Request對象回調函數。
yield 的作用就是把一個函數變成一個 generator(生成器),帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator
4.settings.py
設置文件,可以在里面做User-Agent,Headers,激活管道文件等等
BOT_NAME
(也是項目名稱)。使用 startproject 命令創建項目時會被自動賦值。
SPIDER_MODULES = ['ziruproject.spiders'] NEWSPIDER_MODULE = 'ziruproject.spiders'
爬蟲的文件路徑
USER_AGENT
用戶代理,一般設置這個參數用來偽裝瀏覽器請求
ROBOTSTXT_OBEY
是否遵守ROBOT協議,為False時,表示不遵守,
為True時表示遵守(默認為True)
COOKIES_ENABLED
是否要攜帶cookies,一般情況下,不是必須要攜帶
cookies的請求,我們將這個參數設置為False,(默認為True)
DEFAULT_REQUEST_HEADERS
默認: 如下
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
用于Scrapy HTTP請求的默認標頭
ITEM_PIPELINES
設置并激活管道文件,為了存儲數據使用,
后面的數字表示優先級,數字越小,優先級越高
關于日志信息的設置
LOG_ENABLED
默認: True
是否啟用logging。
LOG_FILE
默認: None
logging輸出的文件名。如果為None,則使用標準錯誤輸出(standard error)。
Logging使用
Scrapy提供了log功能,可以通過 logging 模塊使用。
可以修改配置文件settings.py,任意位置添加下面兩行,效果會清爽很多。
LOG_FILE = "TencentSpider.log"
LOG_LEVEL = "INFO"
5.middleware.py
下載中間件和爬蟲中間件
middleware的使用主要是為了自定義一些第三方組件,是爬蟲和反爬的重要過程
主要有四種:
1.隨機User-Agent
2.自定義隨機cookies
3.enium結合使用
4.自定義隨機ip池
除了一般的scrapy框架之外還有通用爬蟲
通用爬蟲和一般爬蟲的區別主要是多了一個Rule的規則
他的主要參數是:
LinkExtractor中有:
allow:一般設置一個正則表達式,符合該正則表達式的連接,提取該url(常用)
deny:同樣是跟一個正則表達式,符合該正則表達式的連接,不提取該url
(優先級比allow要高)
?allowed_domains:提取的連接,必須在allowed_domains設置的域下
? deny_domains: 提取鏈接時,一定不能提取deny_domains設置的域下
restrict_xpaths:當提取鏈接的時候,我們可以使用xpath語法定位到某些標簽,提取標簽下,
?符合規則的鏈接 (常用)
tags:可以指定要提取哪些標簽
?attrs:可以指定要提取標簽的哪些屬性
?restrict_css:當提取鏈接的時候,我們可以使用css語法定位到某些標簽,提取標簽下,
?符合規則的鏈接 (常用)
還有:
callback='回調函數名稱',
?follow=True | False,? # 表示是否要跟進
爬蟲的步驟
step1:
分析目標網站,根據要提取的目標數據,在items.py中自定義字段
step2:
? ? 在爬蟲文件中:(1)首先設置目標url
? ? ? ? ? ? ? ? ????????????????(2) 解析請求成功的響應結果,提取目標數據,賦值給item,提取新的url,繼續發起請求
step3:
? ? (1) 在設置文件中激活管道
? ? (2) 在管道文件中做數據的過濾和持久化
注意:
1.進入項目一定要先設置虛擬環境
2.首先更改settings的幾個配置
? ? (1).ROBOTSTXT_OBEY
是否遵守ROBOT協議,為False時,表示不遵守,
為True時表示遵守(默認為True)
(2).COOKIES_ENABLED
是否要攜帶cookies,一般情況下,不是必須要攜帶
cookies的請求,我們將這個參數設置為False,(默認為True)
(3).DEFAULT_REQUEST_HEADERS
此設置是設置一個全局的請求頭
默認: 如下
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
(4).DOWNLOAD_DELAY =1(防止訪問過于頻繁)
表示延時下載,一般情況下設為1或2
通用爬蟲:為了全站爬取
通用爬蟲創建項目
scrapy genspider -t crawl 爬蟲名稱 域
通用爬蟲與普通爬蟲的區別就在于多了一個rules規則
rules 規則屬性的參數:是一個元組,可以放多個Rule對象
創建Rule:
LinkExtractor:設置提取規則
(allow,deny,allow_domea..,deny_domea..,restrict_xpath,restrict_css)
callback:設置回調函數
follwer:是否跟進
process_links:設置一個函數,根據正則規則獲取的url,可以在回調函數中獲取到
processs_request:設置一個函數,可以在這個回調方法中攔截所有根據正則規則提取到的url構建的Request對象
注意:
1.設置回調的時候一定不能重寫parse方法
2.要獲取起始url的響應結果 ,必須重寫parse_start_url
3.在設置Rule對象的時候,如果沒有callback回調函數,默認表示跟進
什么情況下會用到通用爬蟲???
當我們提取數據的目標網站的網址很有規律,并且模塊很清晰,我么就可以使用通用爬蟲class
數據持久化之圖片下載
在 ImagesPipeline 類中實現,提供了一個方便并具有額外特性的方法,來下載并本地存儲圖片
首先在setttings里設置一個圖片下載路徑
然后在自定義的圖片下載管道里獲取到這個圖片路徑
第一種:正常的發起請求 ,獲取圖片的二進制文件,保存
第二種:自定義圖片管道,繼承自ImagePipline
? ? 重寫兩個方法:
? ? ? ? def get_media_request(self,item,spider):
? ? ? ? ? ? 獲取圖片地址,發起請求
? ? ? ? def item_completed(self,results,spider,item,....):
? ? ? ? ? ? 在results結果中根據圖片下載狀態,獲取圖片本地存儲的路徑,
? ? ? ? ? ? 將獲取的路徑賦值給item,然后將item返回給其他管道
# 數據持久化:(切記激活管道)
? ? 1.可以自定義數據管道
? ? ? ? def __init__(self,xxx,xxxxx,xxxxx):
? ? ? ? ? ? # 可以設置一些參數,(比如,創健數據庫鏈接,打開文件等等
? ? ? ? @classmethod
? ? ? ? def from_crawler(cls,crawler):
? ? ? ? ? ? crawler:包含了爬蟲的一些核心組件,可以獲取settings中的一些參數
? ? ? ? ? ? return cls(xxx,xxxx,xxxx)
? ? ? ? def open_spider(self,spider):
? ? ? ? ? ? # 可選方法,在爬蟲個開啟的時候會調用
? ? ? ? def process_item(self,item,spider):
? ? ? ? ? ? # 所有的item都會經過這個方法
? ? ? ? ? ? # 在這里做數據持久化(pymongo,pymysql)
? ? ? ? ? ? # 方法一:
? ? ? ? ? ? if isinstance(item,類名)
? ? ? ? ? ? ? ? 做數據插入操作
? ? ? ? ? ? elif isinstance(item,類名)
? ? ? ? ? ? ? ? 做數據插入操作
? ? ? ? ? ? 方法二:
? ? ? ? ? ? ? ? 1.在item對應的類中,我們定義一個方法,返回sql語句和要插入的數據
? ? ? ? ? ? ? ? 2.使用item調用這個方法,得到sql語句和要插入的數據
? ? ? ? ? ? ? ? 3.執行插入操作
? ? ? ? ? ? return item(如果要將item,傳遞給下一個管道,必須要return)
數據持久化之mongodb
首先在settings設置數據庫配置文件
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
數據持久化之mysql
同樣的,我們也把數據庫的配置信息,寫在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):
? ? ? ? #創建mysql連接
? ? ? ? self.client = pymysql.Connect(host,user,pwd,db,charset='utf8')
? ? ? ? #創建游標
? ? ? ? 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還有一個交互終端,我們可以在未啟動spider的情況下嘗試及調試代碼,也可以用來測試XPath或CSS表達式,查看他們的工作方式,方便我們爬取的網頁中提取的數據。
啟動
scrapy shell? 爬取目標網頁
electors選擇器?Scrapy Selectors 內置 XPath 和 CSS Selector 表達式機制?Selector有四個基本的方法,最常用的還是xpath:
xpath(): 傳入xpath表達式,返回該表達式所對應的所有節點的selector list列表
extract(): 序列化該節點為字符串并返回list
css(): 傳入CSS表達式,返回該表達式所對應的所有節點的selector list列表,語法同 BeautifulSoup4
re(): 根據傳入的正則表達式對數據進行提取,返回字符串list列表
scrapy -h 查看所有可用的命令:
scrapy view -h 查看view命令的詳細內容:
scrapy list列出當前項目中所有可用的spider
scrapy runspider xxxx.py在未創建項目的情況下,運行一個編寫在Python文件中的spider。
scrapy version輸出Scrapy版本
Scrapy 的暫停和恢復
爬取大的站點,我們希望能暫停爬取,之后再恢復運行。
scrapy crawl 爬蟲名稱 -s JOBDIR=crawls/爬蟲名稱
如要暫停,直接Ctrl+C即可,若要恢復,再一次運行此代碼即可