學習爬蟲有一段時間了,從Python的Urllib、Urlllib2到scrapy,固然,scrapy的性能且效率是最高的,本身以前也看過一些資料,在此學習總結下。css
Scrapy介紹html
關於scrapypython
scrapy是一個健壯的,能夠從網絡上抓取數據的web框架,只須要一個配置文件就能組合各類組件和配置選項。同時,scrapy是一個基於事件的架構 所以咱們能夠級聯不少操做,包括清理,組織,存儲數據到數據庫,導出數據等。
假設你如今要抓取一個網站,這個網站的每一頁都有一百個條目,Scrapy能夠絕不費勁地同時對這個網站發起16個請求,假如每一個請求須要一秒鐘來完成,就至關於每秒鐘爬取16個頁面,至關於每秒鐘生成了1600個條目,假如要把這些條目同時存儲到雲上,每個條目的存儲須要3秒鐘(假設的),爲了處理這16個請求,就須要運行1600 *3 = 4800個併發的寫入請求,對於一個傳統的多線程程序來講,就須要轉換成4800個線程,這會對系統形成極大的壓力。而對於Scrapy來講,只要你的硬件過關, 4800個併發請求是沒有問題的。git
scrapy的優勢github
Scrapy已經發展了5年有多,已經變得成熟和穩定,除了上面提到的性能優勢外,Scrapy還有如下幾點優勢:
1. Scrapy能夠處理不完整的HTML
你能夠在Scrapy中使用Beautiful Soup或者lxml,但Scrapy已經提供了selectors(一個在lxml的基礎上提供了更高級的接口),能夠高效地處理不完整的HTML代碼。
2. 活躍的Scrapy社區
Scrapy擁有一個活躍的社區,尤爲是在Stack Overflow(https://stackoverflow.com/questions/tagged/Scrapy)上有上千個問題的討論,更多的社區論壇能夠參考這裏:http://Scrapy.org/community/
3. 由社區維護的具備良好架構的代碼
Scrapy要求你用標準的方式去組織你的代碼,因此你在與他人合做時,別人不用苦苦研究你那擁有奇淫技巧的爬蟲。
4. 新特性愈來愈多且質量穩定
經過觀察Scrapy的新聞發佈頁(http://doc.Scrapy.org/en/latest/news.html),就能夠看到在增長的新特性和bug修正。web
Scrapy基礎正則表達式
安裝shell
我一直是在ubuntu下使用scrapy的 下面就說說ubuntu下scrapy的安裝:數據庫
$sudo apt-get update $ sudo apt-get install python-pip python-lxml python-crypto python-cssselect python-openssl python-w3lib python-twisted python-dev libxml2-dev libxslt1-dev zliblg-dev libffi-dev libssl-dev $ sudo pip install scrapy
若是想要得到最新版的話,可使用:json
git clone https://github.com/scrapy/scrapy.git
cd scrapy
python setup.py install
升級scrapy
sudo pip install -upgrade scrapy or sudo easy_install --upgrade scrapy
固然 也有人是想安裝特定的版本的 那麼可使用命令:
sudo pip install scrapy==1.00 or sudo easy_install scrapy==1.00
爬取過程 - URI^2IM
每一個網站都是不同的,那麼使用scrapy爬取時勢必會存在差別。可是,當使用scrapy爬取時,使用最多的是UR^2IM流程,分別是:URL,Request,Response,Items,More URLS。
URL
全部的爬蟲都是從一個起始的URL(也就是你想要爬取的網站地址)開始,當你想要驗證用xpath或者其它解析器來解析這個網頁時,可使用scrapy shell工具來分析。
scrapy shell(scrapy終端)是一個交互式的終端,在未啓動spider的狀況下嘗試及調試爬取代碼,主要測試Xpath和CSS表達式等,查看他們的工做方式以及從爬取的網頁中提取數據,該終端在開發和調試spider時發揮着巨大的做用。
啓動終端:scrapy shell <url>
使用該終端時,可以使用一些快捷命令,以下:
shelp | 打印可用對象及快捷命令的幫助列表 |
fetch(request_or_url) | 根據給定的請求(request)或URL獲取一個新的response,並更新 相關對象 |
view(response) | 在本機的瀏覽器打開給定的response |
可用的scrapy對象,scrapy終端會根據下載的頁面自動建立一些方便使用的對象,包括:
crawler | 當前的crawler對象 |
spider | 處理URL的spider |
request | 最近獲取到的頁面的request對象 |
response | 最近獲取到的頁面的response對象 |
sel | 最近獲取到的response構建的Selector對象 |
settings | 當前的scrapy settings |
終端會話樣例:爬取"https://baidu.com"的頁面。輸入:scrapy shell 'http://www.cnblogs.com/ybjourney/' --nolog,會顯示相應的各個對象的值,進而在In [1]:中輸入:sel.xpath('//div[@class="postTitle"]/a/text()').extract(),驗證xpath表達式。
The Request and The Response(請求和響應)
在上面使用scrapy shell就會發現,只要咱們輸入一個URL,它就能夠自動發送一個GET請求並返回結果。request是一個把url封裝好的對象,response則是一個把網頁返回結果封裝好的對象,response.body的值是網頁的源代碼,response.url是網頁的url地址,還有更多相關的屬性。
Items
爬蟲的目標不僅是在爬取到網頁的源代碼,更重要的是提取網頁的相關信息,對於這些內容,在scrapy中被封裝爲一個Item對象,而後從網頁中提取信息來填充這個Item。
從網頁中提取信息經常使用到的方式有不少,好比正則表達式(re),BeautifulSoup,Xpath等,我經常使用到的就這幾種。
scrapy工程
上面咱們學習了scrapy的一些基礎知識,如今咱們動手建立一個scrapy項目,寫爬蟲~
首先,用命令scrapy startproject yourproject新建一個項目。 cd yourproject
tree
該項目的目錄以下:
__init__.py
items.py
pipelines.py
settings.py
spiders
__init__.py
scrapy.cfg
其中,spiders文件中主要是用來編寫爬蟲(spider)文件,定義了對某個特定網頁的類。其它重要的文件包括:items.py,piplines.py,settings.py,分別的做用以下:
items.py:定義須要抓取並須要後期處理的數據,很像字典;
settings.py:文件配置scrapy,從而修改user-agent,設定爬取時間間隔,設置代理,配置各類中間件等,在反爬蟲時會用到。
piplines.py:用於存放執行後期數據的功能,將數據的爬取和處理分開。items抓取數據以後送到pipline。
創建project就是不斷的對這三個文件進行修改。
編寫爬蟲
在瞭解了scrapy項目的目錄後,接下來就是編寫爬蟲了,在這裏以爬取我博客園第一頁的博客標題、摘要、博客連接爲例進行說明。
定義item
爬蟲以前,必定是要知道你須要爬取到什麼內容,在items.py中定義抓取,在該文件中定義的item並非必定要在每個spider中填充,也不是所有同時使用,由於item中的字段能夠在不一樣的spider文件中使用,也能夠在一個spider文件的不一樣地方使用,你只須要在此定義你須要用到的字段,定義以後在任什麼時候候均可以使用。在該例子中的items.py文件以下:
from scrapy import Item,Field class Mych03Item(Item): Title = Field() Abstract = Field() Link = Field()
寫爬蟲文件
定義了item以後,咱們就能夠寫爬蟲文件了,在spider文件夾中創建相應的文件,咱們能夠開始寫爬蟲了。
首先,在項目的根目錄下根據basic模板建立一個名爲basic的spider,後面的web指的是spider的可運行的域名:
scrapy genspider –t basic basic web
在本項目中的命令是:
scrapy genspider -t basic cnblog cnblogs
這樣就在spiders文件夾中建立了一個cnblog.py的爬蟲文件。
固然能夠本身手寫一個spider,可是從模板裏建立能夠省去很多的時間和減小出錯機率,查看其餘模板的命令:
scrapy genspider -l
使用模板建立的文件以下:
# -*- coding: utf-8 -*- import scrapy class BasicSpider(scrapy.Spider): name = "basic" allowed_domains = ["web"] start_urls = ( 'http://www.web/', ) def parse(self, response): pass
對該spider文件中的幾個變量作出說明:
name:定義的spider名字,該名字在執行這個爬蟲文件時會用到,故應保持名字是惟一的;
allowed_domains:容許爬取的域名列表;
start_urls:爬蟲的起始地址。
建立好了模板文件,就能夠結合以前的內容,編寫爬蟲文件了,編寫cnblog.py文件以下:
# coding:utf-8 import scrapy from mych03.items import Mych03Item from scrapy.selector import Selector from scrapy.utils.response import get_base_url class CnblogSpider(scrapy.Spider): name = "cnblog" allowed_domains = ["cnblogs"] start_urls = ( 'http://www.cnblogs.com/ybjourney/default.html?page=1', ) def parse(self, response): items = [] sel = Selector(response) base_url = get_base_url(response) postTitle = sel.css('div.postTitle') postAbstract = sel.css('div.c_b_p_desc') for index in range(len(postTitle)): item = Mych03Item() item['Title'] = postTitle[index].css("a").xpath(u'text()').extract()[0] item['Link'] = postTitle[index].css('a').xpath('@href').extract()[0] item['Abstract'] = postAbstract.xpath('text()').extract()[0] return items
運行:scrapy crawl spidername
保存文件:scrapy crawl spider -o filename.json/csv
保存以後就能夠在項目的根目錄下找到你所保存的.csv或者.json文件了。
Spider的運行原理
咱們寫了爬蟲文件,如今,結合scrapy項目文件目錄,對Spider的運行原理進行說明:
首先要將指定的初始URL封裝成Request對象,而且指定在網頁返回該請求的內容後應該用哪一個函數來處理網頁的內容。通常都會調用start_request()函數,對start_urls中的URL分別生成一個Request對象,並使用callback變量指定相應的parse()函數做爲回調函數。
在回調函數中,處理response變量,返回item對象,一個字典,或者Request對象(能夠指定callback,指定一個回調函數,也就是在處理完這個Request以後生成的response會傳送到回調函數中處理)。
在回調函數中,使用Xpath等類提取網頁中須要的內容,存入item。
從spider中返回的item寫入文件或者數據庫中。
若是你看到這裏,那麼恭喜你,已經會寫一個簡單的爬蟲了。