C語言中文網 目錄

Python Scrapy爬蟲項目開發過程詳解

通過前面的 Scrapy shell 調試,已經演示了使用 XPath 從 HTML 文檔中提取信息的方法,只要將這些調試的測試代碼放在 Spider 中,即可實現真正的 Scrapy 爬蟲。

基于 Scrapy 項目開發爬蟲大致需要如下幾個步驟:
  1. 定義 Item 類。該類僅僅用于定義項目需要爬取的 N 個屬性。比如該項目需要爬取工作名稱、工資、招聘公司等信息,則可以在 items.py 中增加如下類定義:
    import scrapy
    
    class ZhipinspiderItem(scrapy.Item):
        # 工作名稱
        title = scrapy.Field()
        # 工資
        salary = scrapy.Field()
        # 招聘公司
        company = scrapy.Field()
        # 工作詳細鏈接
        url = scrapy.Field()
        # 工作地點
        work_addr = scrapy.Field()
        # 行業
        industry = scrapy.Field()
        # 公司規模
        company_size = scrapy.Field()
        # 招聘人
        recruiter = scrapy.Field()
        # 發布時間
        publish_date = scrapy.Field()
    上面程序中,第 3 行代碼表明所有的 Item 類都需要繼承 scrapy.Item 類,接下來就為所有需要爬取的信息定義對應的屬性,每個屬性都是一個 scrapy.Field 對象。

    該 Item 類只是一個作為數據傳輸對象(DTO)的類,因此定義該類非常簡單。
  2. 編寫 Spider 類。應該將該 Spider 類文件放在 spiders 目錄下。這一步是爬蟲開發的關鍵,需要使用 XPath 或 CSS 選擇器來提取 HTML 頁面中感興趣的信息。

    Scrapy 為創建 Spider 提供了 scrapy genspider 命令,該命令的語法格式如下:

    scrapy genspider [options] <name> <domain>

    在命令行窗口中進入 ZhipinSpider 目錄下,然后執行如下命令即可創建一個 Spider:

    scrapy genspider job_position "zhipin.com"

    運行上面命令,即可在 ZhipinSpider 項目的 ZhipinSpider/spider 目錄下找到一個 job_position.py 文件,打開該文件可以看到如下內容:
    import scrapy
    
    class JobPositionSpider(scrapy.Spider):
        # 定義該Spider的名字
        name = 'job_position'
        # 定義該Spider允許爬取的域名
        allowed_domains = ['zhipin.com']
        # 定義該Spider爬取的首頁列表
        start_urls = ['https://www.zhipin.com/c101280100/h_101280100/']
       
        # 該方法負責提取response所包含的信息
        def parse(self, response):
            pass
    上面程序就是 Spider 類的模板,該類的 name 屬性用于指定該 Spider 的名字;allow_domains 用于限制該 Spider 所爬取的域名;start_urls 指定該 Spider 會自動爬取的頁面 URL。

    Spider 需要繼承 scrapy.Spider,并重寫它的 parse(self, response) 方法(如上面程序所示)。從該類來看,我們看不到發送請求、獲取響應的代碼,這也正是 Scrapy 的魅力所在,即只要把所有需要爬取的頁面 URL 定義在 start_urls 列表中,Scrapy 的下載中間件就會負責從網絡上下載數據,并將所有數據傳給 parse(self, response) 方法的 response 參數。

    注意,如果在 Windows 上使用 genspider 命令來生成爬蟲類,則容易引發 SyntaxError:(unicode error)'utf-8' codec can’t decode byte 0xb9 in position 0: invalid start byte 錯誤,這是由于 Windows 采用了 GBK 字符集。因此,需要手動將該 Spider 類保存為 UTF-8 字符集。

    一言以蔽之,開發者只要在 start_urls 列表中列出所有需要 Spider 爬取的頁面 URL,這些頁面的數據就會“自動”傳給 parse(self, response) 方法的 response 參數。

    因此,開發者主要就是做兩件事情:
    • 將要爬取的各頁面 URL 定義在 start_urls 列表中。
    • 在 parse(self, response) 方法中通過 XPath 或 CSS 選擇器提取項目感興趣的信息。

    下面將 job_position.py 文件改為如下形式:
    import scrapy
    from ZhipinSpider.items import ZhipinspiderItem
    
    class JobPositionSpider(scrapy.Spider):
        # 定義該Spider的名字
        name = 'job_position'
        # 定義該Spider允許爬取的域名
        allowed_domains = ['zhipin.com']
        # 定義該Spider爬取的首頁列表
        start_urls = ['https://www.zhipin.com/c101280100/h_101280100/']
       
        # 該方法負責提取response所包含的信息
        # response代表下載器從start_urls中每個URL下載得到的響應
        def parse(self, response):
            # 遍歷頁面上所有//div[@class="job-primary"]節點
            for job_primary in response.xpath('//div[@class="job-primary"]'):
                item = ZhipinspiderItem()
                # 匹配//div[@class="job-primary"]節點下/div[@class="info-primary"]節點
                # 也就是匹配到包含工作信息的<div.../>元素
                info_primary = job_primary.xpath('./div[@class="info-primary"]')
                item['title'] = info_primary.xpath('./h3/a/div[@class="job-title"]/text()').extract_first()
                item['salary'] = info_primary.xpath('./h3/a/span[@class="red"]/text()').extract_first()
                item['work_addr'] = info_primary.xpath('./p/text()').extract_first()
                item['url'] = info_primary.xpath('./h3/a/@href').extract_first()
                # 匹配//div[@class="job-primary"]節點下./div[@class="info-company"]節點下
                # 的/div[@class="company-text"]的節點
                # 也就是匹配到包含公司信息的<div.../>元素
                company_text = job_primary.xpath('./div[@class="info-company"]' +
                    '/div[@class="company-text"]')
                item['company'] = company_text.xpath('./h3/a/text()').extract_first()
                company_info = company_text.xpath('./p/text()').extract()
                if company_info and len(company_info) > 0:
                    item['industry'] = company_info[0]
                if company_info and len(company_info) > 2:
                    item['company_size'] = company_info[2]
                # 匹配//div[@class="job-primary"]節點下./div[@class="info-publis"]節點下
                # 也就是匹配到包含發布人信息的<div.../>元素
                info_publis = job_primary.xpath('./div[@class="info-publis"]')
                item['recruiter'] = info_publis.xpath('./h3/text()').extract_first()
                item['publish_date'] = info_publis.xpath('./p/text()').extract_first()
                yield item
    上面程序中,第 10 行代碼修改了 start_urls 列表,重新定義了該 Spider 需要爬取的首頁;接下來程序重寫了 Spider 的 parse(self, response) 方法。

    程序第 16 行代碼使用 XPath 匹配所有的 '//div[@class="job-primary"]' 節點(每個節點都包含一份招聘信息)。因此,程序使用循環遍歷每個 '//div[@class="job-primary"]' 節點,為每個節點都建立一個 ZhipinspiderItem 對象,并從該節點中提取項目感興趣的信息存入 ZhipinspiderItem 對象中。

    程序最后一行代碼使用 yield 語句將 item 對象返回給 Scrapy 引擎。此處不能使用 return,因為 return 會導致整個方法返回,循環不能繼續執行,而 yield 將會創建一個生成器。

    Spider 使用 yield 將 item 返回給 Scrapy 引擎之后,Scrapy 引擎將這些 item 收集起來傳給項目的 Pipeline,因此自然就到了使用 Scrapy 開發爬蟲的第二步。
  3. 編寫 pipelines.py 文件,該文件負責將所爬取的數據寫入文件或數據庫中。

    現在開始修改 pipelines.py 文件。為了簡化開發,只在控制臺打印 item 數據。下面是修改后的 pipelines.py 文件的內容。
    class ZhipinspiderPipeline(object):
        def process_item(self, item, spider):
            print("工作:" , item['title'])
            print("工資:" , item['salary'])
            print("工作地點:" , item['work_addr'])
            print("詳情鏈接:" , item['url'])
    
            print("公司:" , item['company'])
            print("行業:" , item['industry'])
            print("公司規模:" , item['company_size'])
    
            print("招聘人:" , item['recruiter'])
            print("發布日期:" , item['publish_date'])
    從上面第 2 行代碼可以看到,ZhipinspiderPipeline 主要就是實現 process_item(self, item, spider) 方法,該方法的 item、spider 參數都由 Scrapy 引擎傳入,Scrapy 引擎會自動將 Spider“捕獲”的所有 item 逐個傳給 process_item(self, item, spider) 方法,因此該方法只需處理單個的 item 即可(不管爬蟲總共爬取了多少個 item,process_item(self, item, spider) 方法只處理一個即可)。

經過上面三個步驟,基于 Scrapy 的爬蟲基本開發完成。下面還需要修改 settings.py 文件進行一些簡單的配置,比如增加 User-Agent 頭。取消 settings.py 文件中如下代碼行的注釋,并將這些代碼行改為如下形式:
BOT_NAME = 'ZhipinSpider'

SPIDER_MODULES = ['ZhipinSpider.spiders']
NEWSPIDER_MODULE = 'ZhipinSpider.spiders'
ROBOTSTXT_OBEY = True
# 配置默認的請求頭
DEFAULT_REQUEST_HEADERS = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}
# 配置使用Pipeline
ITEM_PIPELINES = {
    'ZhipinSpider.pipelines.ZhipinspiderPipeline': 300,
}
回顧一下上面的開發過程,使用 Scrapy 開發爬蟲的核心工作就是三步:
  • 定義 Item 類。由于 Item 只是一個 DTO 對象,因此定義 Item 類很簡單。
  • 開發 Spider 類,這一步是核心。Spider 使用 XPath 從頁面中提取項目所需的信息,并用這些信息來封裝 Item 對象。
  • 開發 Pipeline。Pipeline 負責處理 Spider 獲取的 Item 對象。

注意,所有修改過的源文件(尤其是添加了中文注釋的文件)都需要手動保存為 UTF-8 字符集,否則在運行爬蟲時會出現錯誤。

經過上面步驟,這個基于 Scrapy 的 Spider 已經開發完成。在命令行窗口中進入 ZhipinSpider 項目目錄下(不是進入 ZhipinSpider/ZhipinSpider 目錄下),執行如下命令來啟動 Spider:

scrapy crawl job_position

上面 scrapy crawl 命令中的 job_position 就是前面定義的 Spider 名稱(通過 JobPositionSpider 類的 name 屬性指定)。運行上面命令,可以看到如圖 1 所示的輸出結果。


圖 1 爬取第一頁數據

從圖 1 可以看出,該爬蟲已經順利爬取了 start_urls 列表所給出頁面中的工作信息。但問題又出現了,該爬蟲并未繼續爬取下一頁的工作信息。

爬蟲可以自動爬取下一頁信息嗎?答案是肯定的。在提取完 response 中的所有“工作信息”之后,Spider 可以使用 XPath 找到頁面中代表“下一頁”的鏈接,然后使用 Request 發送請求即可。

通過瀏覽器查看源代碼,可以看到 https://www.zhipin.com/c101280100/h_101280100/ 頁面中包含分頁信息的源代碼,如圖 2 所示。


圖 2 頁面中包含分頁信息的源代碼

從圖 2 可以看出,頁面中“下一頁”元素的 XPath 為 //div[@class='page']/a [@class='next'],因此程序需要在 JobPositionSpider 類的 parse(self, response) 方法的后面添加如下代碼:
# 解析下一頁的鏈接
new_links = response.xpath('//div[@class="page"]/a[@class="next"]/@href').extract()
if new_links and len(new_links) > 0:
    # 獲取下一頁的鏈接
    new_link = new_links[0]
    # 再次發送請求獲取下一頁數據
    yield scrapy.Request("https://www.zhipin.com" + new_link, callback=self.parse)
應該將上面這段代碼放在 parse(self, response) 方法的后面,這樣可以保證 Spider 在爬取頁面中所有項目感興趣的工作信息之后,才會向下一個頁面發送請求。

上面程序中第 2 行代碼解析頁面中的“下一頁”鏈接;第 7 行代碼顯式使用 scrapy.Request 來發送請求,并指定使用 self.parse 方法來解析服務器響應數據。需要說明的是,這是一個遞歸操作,即每當 Spider 解析完頁面中項目感興趣的工作信息之后,它總會再次請求“下一頁”數據,通過這種方式即可爬取廣州地區所有的熱門職位信息。

再次運行 scrapy crawl job_position 命令來啟動爬蟲,即可看到該爬蟲成功爬取了 10 頁職位信息,這是因為該頁面默認只提供 10 頁職位信息。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo