爬蟲之scrapy

1、項目簡單流程

一、建立項目

scrapy startproject 項目名css

二、建立Spider

cd 項目名html

scrapy genspider 爬蟲名 域名python

class YokaSpider(scrapy.Spider):
    name = 'yoka'
    allowed_domains = ['www.yoka.com/fashion/']
    start_urls = ['http://www.yoka.com/fashion/']
    
    def parse(self,response):
        pass

建立的Spider類需繼承scrapy.Spidermysql

name:爬蟲名正則表達式

allowed_domains:容許爬取的域名,不在域名下的請求連接會被過濾掉sql

start_urls:Spider啓動時爬取的url列表,初始請求由它來定義數據庫

parse:默認狀況下, start_urls裏的連接請求完成下載後,返回的響應就會做爲惟一的參數傳遞給這個函數。該方法負責解析返回的響應、提取數據、進一步生成要處理的請求json

三、建立Item

Item是保存爬取數據的容器,使用方法和字典相似,不過多了額外的保護機制,能夠避免拼寫錯誤和定義字段錯誤api

建立的Item類需繼承scrapy.Item,並定義類型爲scrapy.Field的字段網絡

class YokadapeiItem(scrapy.Item):
    text= scrapy.Field()
    tags=scrapy.Field()

四、解析Response

五、使用Item

①實例化 item=YokadapeiItem()

②賦值item['text']=...  item['tags']=...

③yield item

六、後續Request

使用scrapy.Request方法

yield scrapy.Request(url=請求鏈接,callback=回調函數)

七、運行

scrapy crawl 爬蟲名

八、保存到文件

scrapy crawl 爬蟲名 -o 文件名.後綴名(json、csv、xml等)

九、使用Item Pipeline

Item生成後,會自動被送到Item Pipeline進行處理

Item Pipeline的做用

①清理HTML數據

②驗證爬取數據,檢查爬取字段

③查重並丟棄重複內容

④將爬取結果保存到數據庫

實現Item Pipeline

①定義一個類並實現process_item()方法 ---必須返回包含數據的字典或Item對象,或拋出DropItem異常

該方法有兩個參數,第一個是item,每次Spider生成的Item都會做爲參數傳過來,第二個是spider,就是Spider的實例

接下來,咱們是實現一個Item Pipeline篩調長度大於25的title

from scrapy.exceptions import DropItem

class TestSPipeline(object):
    def __init__(self):
        self.limit=25
    def process_item(self, item, spider):
        #判斷該字段是否存在
        if item['title']:
            if len(item['title']) > self.limit:
                item['title']=item['title'][0:self.limit].rstrip() + '...'
            return item
        else:
            return DropItem("Missing title")

 ②將處理後的item存入MySQL

建立MysqlPipeline類

import pymsql

class MysqlPipeline(object):
    def __init__(self,mysql_host,mysql_port,mysql_db,mysql_user,mysql_password,mysql_table):
        self.mysql_host=mysql_host
        self.mysql_port=mysql_port
        self.mysql_db=mysql_db
        self.mysql_table=mysql_table
        self.mysql_user=mysql_user
        self.mysql_password=mysql_password

    #類方法,用classmethod標識,經過參數crawler拿到全局配置的每一個配置信息
    #再settings中咱們能夠定義MYSQL_HOST和MYSQL_PORT等來指定MySQL鏈接須要的地址和端口等信息
    @classmethod
    def from_crawler(cls,crawler):
        return cls(
            mysql_host=crawler.settings.get('MYSQL_HOST'),
            mysql_port=crawler.settings.get('PORT'),
            mysql_db=crawler.settings.get('MYSQL_DB'),
            mysql_user=crawler.settings.get('MYSQL_USER'),
            mysql_password=crawler.settings.get('MYSQL_PASSWORD'),
            mysql_table=crawler.settings.get('MYSQL_TABLE'),
        )

    def open_spider(self,spider):
        self.conn = pymysql.connect(host=self.mysql_host,port=self.mysql_port,
                                    user=self.mysql_user,password=self.mysql_password,
                                    database=self.mysql_db,charset='utf8')
        self.cur=self.conn.cursor()

    def process_item(self,item,spider):
        dc=dict(item)
        for v in dc.values():
            sql="insert into %s (title) values ('%s')"%(self.mysql_table,v)
            self.cur.execute(sql)
            self.conn.commit()
            return item

    def close_spider(self,spider):
        self.conn.close()

在配置文件settings中

#數字越小越先被調用
ITEM_PIPELINES = {
   'test_s.pipelines.TestSPipeline': 300,
   'test_s.pipelines.MysqlPipeline':400,
}
MYSQL_HOST='localhost'
MYSQL_PORT='3306'
MYSQL_DB='scrapy'
MYSQL_TABLE='titles'
MYSQL_USER='root'
MYSQL_PASSWORD='123456'

2、Selector的用法

xpath、css、正則

3、Spider的用法

一、Spider運行流程 ---Spider主要作兩件事[1]、定義爬取網站的動做 [2]、分析爬取下來的網頁

 

二、Spider類 ---提供了start_requests()方法的默認實現 -> 讀取start_urls屬性,並根據返回的結果調用parse()方法解析結果

屬性:

①name:爬蟲名稱

②allowed_domains:容許爬蟲的域名

③start_urls:起始URL列表,當沒有實現start_requests()時,默認會從這個列表開始抓取

③custom_settings:字典,專屬本Spider的配置,覆蓋項目全局的設置。此設置必須在初始化以前被更新,必須定義成類變量

④crawler:由from_crawler()方法設置的,表明本Spider類對應的Crawler對象,利用它能夠獲取項目的一些配置信息

⑤settings;Settings對象,能夠直接獲取項目的全局設置變量

方法:

①start_requests():生成初始請求,必須返回一個可迭代對象。默認使用start_urls裏的URL來構造Request(GET請求方式),

若想以POST方式訪問某個站點,能夠直接重寫該方法,發送POST請求時使用FormRequest

②parse():當Response沒有指定回調函數時,該方法會默認被調用。該方法需返回一個包含Request或Item的可迭代對象

③closed():當Spider關閉時,該方法會被調用

4、Downloader Middleware的用法

Scrapy內置了許多Downloader Middleware,被定義在DOWNLOADER_MIDDLEWARES_BASE變量中,

能夠在settings修改DOWNLOADER_MIDDLEWARES以及禁用(將該中間件優先級設置爲None)內置的Downloader Middleware

在整個架構中的位置爲:

①在Request執行下載以前對其進行修改

②在生成Response被Spider解析以前對其進行修改

能夠修改User-Agent、處理重定向、設置代理、失敗重試、設置Cookies等

核心方法有三個:process_request(request,spider)、process_response(request,response,spider)、process_exception(request,exception,spider)

實現至少一個方法,就能夠定義一個Downloader Middleware

一、process_request(request,spider)

在Request從隊列裏調度出來到Downloader下載執行以前,均可以用process_request()方法對Request進行處理

參數:①request:Request對象,即被處理的Request

   ②spider:Spider對象,即此Request對應的Spider

---返回值必須爲None、Response對象、Request對象 之一,或拋出IgnoreRequest異常

①返回None時,不一樣的Downloader Middleware按照設置的優先級順序依次對Request進行修改,最後送至Downloader執行

②返回Response對象時,更低優先級的Downloader Middleware的process_request()和process_exception()不會繼續調用,每一個Downloader Middleware的process_response()依次被調用,調用完畢後,直接將Response對象發送給Spider來處理

③返回Request對象時,更低優先級的Downloader Middleware的process_request()中止執行,該Request會從新放到調度隊列裏,至關於全新的Request

④IgnoreRequest異常拋出,全部的Downloader Middleware的process_exception()依次執行,若沒有一個方法處理該異常,那麼Request的errorback()方法就會回調。若是該異常尚未被處理,那麼它便會被忽略

二、process_response(request,response,spider)

參數:①request:Request對象,此Response對應的Request

   ②response:Response對象,此被處理的Response

   ③spider:Spider對象,此Response對應的Spider

不一樣的返回狀況:

①返回Request對象時,更低優先級的Downloader Middleware的process_response()不會被調用,該Request會從新放到調度隊列裏,至關於全新的Request

②返回Response對象時,更低優先級的Downloader Middleware的process_response()繼續調用,繼續對該Response對象進行處理

③IgnoreRequest異常拋出,則Request的errorback()方法就會回調。若是該異常尚未被處理,那麼它便會被忽略

三、process_exception(request,exception,spider)

參數:①request:Request對象,產生異常的Request

   ②exception:Exception對象,即拋出的異常

   ③spider:Spider對象,即Request對應的Spider

不一樣的返回狀況:

①返回爲None時,更低優先級的Downloader Middleware的process_exception()會被繼續調用,直到全部的方法都被調度完畢

②返回Response對象時,更低優先級的Downloader Middleware的process_exception()再也不繼續調用,每一個Downloader Middleware的process_response()轉而被依次調用

③返回Request對象時,更低優先級的Downloader Middleware的process_exception()也再也不繼續調用,該Request會從新放到調度隊列裏,至關於全新的Request

四、實戰:

在parse()中能夠用 response.request.headers 查看請求頭信息

如 b'User-Agent': [b'Scrapy/1.5.1 (+https://scrapy.org)'], 使用的Use-Agent是Scrapy/1.5.1 (+https://scrapy.org),它是由Scrapy內置的UserAgentMiddleware設置的

from scrapy import signals

class UserAgentMiddleware(object):
    """This middleware allows spiders to override the user_agent"""

    def __init__(self, user_agent='Scrapy'):
        self.user_agent = user_agent

    @classmethod
    def from_crawler(cls, crawler):
        o = cls(crawler.settings['USER_AGENT'])
        crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
        return o

    def spider_opened(self, spider):
        self.user_agent = getattr(spider, 'user_agent', self.user_agent)

    def process_request(self, request, spider):
        if self.user_agent:
            request.headers.setdefault(b'User-Agent', self.user_agent)

修改User-Agent有兩種方式①直接修改在settings的USER_AGENT變量 ②經過Downloader Middleware的process_request()來修改

如需設置隨機的User-Agent,須要使用第二種方法

class RandomUserAgentMiddleware(object):

    def __init__(self):
        self.user_agents = [
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
            "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
            "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
            "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
            "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
            "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
            "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
            "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
            "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",
            "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",
            "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
            "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre",
            "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
            "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
            ]

    def process_request(self, request, spider):
        request.headers['User-Agent']=random.choice(self.user_agents)

 Downloader Middleware組件很是重要,是作異常處理和應對反爬處理的核心。後面將用它來處理代理、Cookies等內容

5、Spider Middleware的用法

和Downloader Middleware同樣,Scrapy內置了許多Spider Middleware,被定義在SPIDER_MIDDLEWARES_BASE變量中,

能夠在settings修改SPIDER_MIDDLEWARES,會和SPIDER_MIDDLEWARES_BASE定義的Spider Middleware合併

在整個架構中的位置爲:

①在Response發送給Spider以前對Response進行處理

②在Request發送給Scheduler以前對Request進行處理

③在Item發送給Item Pipeline以前對Item進行處理

核心方法有四個:process_spider_input(response,spider)、process_spider_output(response,result,spider)、process_spider_exception(response,exception,spider)、process_start_request(start_request,spider),實現至少一個方法,就能夠定義一個Spider Middleware

一、process_spider_input(response,spider)

當Response被Spider Middleware處理時,process_spider_input()被調用

參數:①response:Response對象,即被處理的Response

   ②spider:Spider對象,即該Response對應的Spider

不一樣的返回狀況:

①返回None時,Scrapy將會繼續處理該Response,調用全部其餘的Spider Middleware,直到Spider處理該Response

②拋出異常時,Scrapy將不會調用任何其餘的Spider Middleware的process_spider_input(),而調用Request的errback(),errback的輸出將從新輸入到中間件中,使用process_spider_output()來處理,當其拋出異常時則調用process_spider_exception()來處理

二、process_spider_output(response,result,spider)

當Spider處理Response返回結果時,process_spider_output()被調用

參數:①response:Response對象,即生成該輸出的Response

   ②result:包含Request或Item對象的可迭代對象,即Spider返回的結果

   ③spider:Spider對象,即其結果對應的Spider

   該方法必須返回包含Request或Item對象的可迭代對象。

三、process_spider_exception(response,exception,spider)

當Spider或Spider Middleware的process_spider_input()拋出異常時,process_spider_exception()被調用

參數:①response:Response對象,即異常被拋出時被處理的Response

   ②exception:Exception對象,即被拋出的異常

   ③spider:Spider對象,即拋出該異常的Spider

不一樣的返回狀況:

①返回None時,Scrapy將會繼續處理該異常,調用其餘Spider Middleware中的process_spider_exception(),直到全部的Spider Middleware都被調用

②返回包含Request或Item對象的可迭代對象時,則其餘Spider Middleware中的process_spider_output()被調用,其餘的process_spider_exception()不會被調用

四、process_start_request(start_request,spider)

該方法以Spider啓動的Request爲參數時被調用,執行過程相似於process_spider_output(),不過沒有相關聯的Response,而且必須返回Request

參數:①start_request:包含Request的可迭代對象,即Start Request

   ②spider:Spider對象,即Start Request所屬的Spider

   該方法必須返回另外一個包含Request對象的可迭代對象

Spider Middleware的使用頻率不如Downloader Middleware高,在必要的狀況下它能夠用來方便數據的處理

6、Item Pipeline的用法

當Spider解析完Response以後,Item就會傳遞到Item Pipeline,被定義的Item Pipeline組件會順次調用。

Item Pipeline的做用:

    ①清理HTML數據

    ②驗證爬取數據,檢查爬取字段

    ③查重並丟棄重複內容

    ④將爬取結果保存到數據庫

核心方法有四個,必需要實現process_item(item,spider),其餘還有幾個比較實用的方法,open_spider(spider)、close_spider(spider)、from_crawler(cls,crawler)

一、process_item(item,spider)

被定義的Item Pipeline會默認調用該方法對Item進行處理

參數:①item:Item對象,即被處理的Item

   ②spider:Spider對象,即生成該Item的Spider

不一樣的返回狀況:

①返回Item對象時,此Item會被更低優先級的Item Pipeline的process_item()處理,直到全部的方法被調用完畢

②拋出DropItem異常,那麼此Item會被丟棄,再也不進行處理

二、open_spider(spider)

該方法實在Spider開啓的時候被自動調用的。咱們能夠在這裏作一些初始化操做,如開啓數據庫鏈接等

參數:spider:被開啓的Spider對象

三、close_spider(spider)

該方法實在Spider關閉的時候被自動調用的。咱們能夠在這裏作一些收尾工做,如關閉數據庫鏈接等

參數:spider:被關閉的Spider對象

四、from_crawler(cls,crawler)

類方法,用@classmethod標識,是一種依賴注入的方式。

參數:①crawler:經過crawler對象,咱們能夠拿到Scrapy的全部核心組件,如全局配置的每一個信息,而後建立一個Pipeline實例

   ②cls:就是Class

   最後返回一個Class實例

7、通用爬蟲

一、CrawlSpider

CrawlSpider繼承Spider類,除了Spider類的全部屬性和方法,還提供了很是重要的屬性和方法

①rules:爬取規則的屬性,包含一個或多個Rule對象的列表。每一個Rule對爬取網站的動做都作了定義,CrawlSpider會讀取rules的每個Rule並進行解析

②parse_start_url():可重寫的方法。當start_urls裏對應的Request獲得Response時,該方法被調用,它會分析Response並返回Item對象或者Request對象

最重要的是Rule的定義:

scrapy.contrib.spiders下的Rule類

class Rule(object):

    def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):  

參數:

①link_extractor:Link Extractor對象,經過它提取連接並自動生成Request。它又是一個數據結構,經常使用LxmlLinkExtractor對象做爲參數。

scrapy.linkextractors.lxmlhtml下的LxmlLinkExtractor類

class LxmlLinkExtractor(FilteringLinkExtractor):

    def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(),
                 tags=('a', 'area'), attrs=('href',), canonicalize=False,
                 unique=True, process_value=None, deny_extensions=None, restrict_css=(),
                 strip=True):

  [1]、allow是正則表達式或正則表達式列表,符合的連接才被跟進,deny則相反

  [2]、allow_domains是域名白名單,deny_domains則相反

  [3]、restrict_xpaths、restrict_css xpath和css表達式或其列表,用xpath或css提取連接

②callback:回調函數,注意,避免使用parse()做爲回調函數

③cb_kwargs:字典,包含傳遞給回調函數的參數

④follow:布爾值,指定根據該規則從response提取的連接是否須要跟進。若callback爲None,follow默認爲True,不然默認爲False

⑤process_links:指定處理函數,從link_extractor中獲取連接列表時,該函數將會調用,主要用於過濾

⑥process_request:一樣指定處理函數,根據該Rule提取到每一個Request時,該函數都會調用,對Request進行處理。該函數必須返回Request或None

二、Item Loader

Item提供的是保存抓取數據的容器,Item Loader提供的是填充容器的機制。數據的提取會變得更加規則化。

scrapy.loader下的ItemLoader類

class ItemLoader(object):

    default_item_class = Item
    default_input_processor = Identity()
    default_output_processor = Identity()
    default_selector_class = Selector

    def __init__(self, item=None, selector=None, response=None, parent=None, **context):

返回一個新的Item Loader來填充給定的Item,若沒有給出Item,則使用中的類自動實例化default_item_class,用selector、response來使用選擇器或響應參數實例化

參數:

①item:Item對象,能夠調用add_xpath()、add_css()、add_value()等方法來填充Item對象

②selector:Selector對象,用來提取填充數據的選擇器

③response:Response對象,用於使用構造選擇器的Response

 

 

 

本文參考文獻:[1]崔慶才.python3網絡爬蟲開發實戰[M].北京:人民郵電出版社,2018:468-541.

相關文章
相關標籤/搜索