python網路爬蟲(14)使用Scrapy搭建爬蟲框架

噓,小點聲發表於2019-07-27

目的意義

爬蟲框架也許能簡化工作量,提高效率等。scrapy是一款方便好用,擴充方便的框架。

本文將使用scrapy框架,示例爬取自己部落格中的文章內容。

說明

學習和模仿來源:https://book.douban.com/subject/27061630/。

建立scrapy工程

首先當然要確定好,有沒有完成安裝scrapy。在windows下,使用pip install scrapy,慢慢等所有依賴和scrapy安裝完畢即可。然後輸入scrapy到cmd中測試。

建立工程使用scrapy startproject myTestProject,會在工程下生成檔案。

一些介紹說明

在生成的檔案中,

建立爬蟲模組-下載

在路徑./myTestProject/spiders下,放置使用者自定義爬蟲模組,並定義好name,start_urls,parse()。

如在spiders目錄下建立檔案CnblogSpider.py,並填入以下:

import scrapy
class CnblogsSpider(scrapy.Spider):
    name="cnblogs"
    start_urls=["https://www.cnblogs.com/bai2018/default.html?page=1"]
    def parse(self,response):
        pass

 在cmd中,切換到./myTestProject/myTestProject下,再執行scrapy crawl cnblogs(name)測試,觀察是否報錯,響應程式碼是否為200。其中的parse中引數response用於解析資料,讀取資料等。

強化爬蟲模組-解析

在CnblogsSpider類中的parse方法下,新增解析功能。通過xpath、css、extract、re等方法,完成解析。

調取元素審查分析以後新增,成為以下程式碼:

import scrapy
class CnblogsSpider(scrapy.Spider):
    name="cnblogs"
    start_urls=["https://www.cnblogs.com/bai2018/"]
    def parse(self,response):
        papers=response.xpath(".//*[@class='day']")
        for paper in papers:
            url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
            title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
            time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
            content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
            print(url,title,time,content)
        pass

 找到頁面中,class為day的部分,然後再找到其中各個部分,提取出來,最後通過print方案輸出用於測試。

在正確的目錄下,使用cmd執行scrapy crawl cnblogs,完成測試,並觀察顯示資訊中的print內容是否符合要求。

強化爬蟲模組-包裝資料

包裝資料的目的是儲存資料。scrapy使用Item類來滿足這樣的需求。

框架中的items.py用於定義儲存資料的Item類。

在items.py中修改MytestprojectItem類,成為以下程式碼:

import scrapy
class MytestprojectItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    url=scrapy.Field()
    time=scrapy.Field()
    title=scrapy.Field()
    content=scrapy.Field()
    pass

 然後修改CnblogsSpider.py,成為以下內容:

import scrapy
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):
    name="cnblogs"
    start_urls=["https://www.cnblogs.com/bai2018/"]
    def parse(self,response):
        papers=response.xpath(".//*[@class='day']")
        for paper in papers:
            url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
            title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
            time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
            content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
            
            item=MytestprojectItem(url=url,title=title,time=time,content=content)
            yield item
        pass

 將提取出的內容封裝成Item物件,使用關鍵字yield提交。

強化爬蟲模組-翻頁

有時候就是需要翻頁,以獲取更多資料,然後解析。

修改CnblogsSpider.py,成為以下內容:

import scrapy
from scrapy import Selector
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):
    name="cnblogs"
    allowd_domains=["cnblogs.com"]
    start_urls=["https://www.cnblogs.com/bai2018/"]
    def parse(self,response):
        papers=response.xpath(".//*[@class='day']")
        for paper in papers:
            url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
            title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
            time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
            content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
            
            item=MytestprojectItem(url=url,title=title,time=time,content=content)
            yield item
        next_page=Selector(response).re(u'<a href="(\S*)">下一頁</a>')
        if next_page:
            yield scrapy.Request(url=next_page[0],callback=self.parse)
        pass

在scrapy的選擇器方面,使用xpath和css,可以直接將CnblogsSpider下的parse方法中的response引數使用,如response.xpath或response.css。

而更通用的方式是:使用Selector(response).xxx。針對re則為Selector(response).re。

關於yield的說明:https://blog.csdn.net/mieleizhi0522/article/details/82142856

強化爬蟲模組-儲存

當Item在Spider中被收集時候,會傳遞到Item Pipeline。

修改pipelines.py成為以下內容:

import json
from scrapy.exceptions import DropItem
class MytestprojectPipeline(object):
    def __init__(self):
        self.file=open('papers.json','wb')
    def process_item(self, item, spider):
        if item['title']:
            line=json.dumps(dict(item))+"\n"
            self.file.write(line.encode())
            return item
        else:
            raise DropItem("Missing title in %s"%item)

 重新實現process_item方法,收集item和該item對應的spider。然後建立papers.json,轉化item為字典,儲存到json表中。

另外,根據提示開啟pipelines.py的開關。在settings.py中,使能ITEM_PIPELINES的開關如下:

然後在cmd中執行scrapy crawl cnblogs即可

 另外,還可以使用scrapy crawl cnblogs -o papers.csv進行儲存為csv檔案。

需要更改編碼,將csv檔案以記事本方式重新開啟,更正編碼後重新儲存,檢視即可。

 強化爬蟲模組-影象地址

設定setting.py

ITEM_PIPELINES = {
    'myTestProject.pipelines.MytestprojectPipeline':300,
    'scrapy.pipelines.images.ImagesPipeline':1
}
IAMGES_STORE=".//cnblogs"
IMAGES_URLS_FIELD = 'cimage_urls'
IMAGES_RESULT_FIELD = 'cimages'
IMAGES_EXPIRES = 30
IMAGES_THUMBS = {
    'small': (50, 50),
    'big': (270, 270)
}

 修改items.py為:

import scrapy
class MytestprojectItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    url=scrapy.Field()
    time=scrapy.Field()
    title=scrapy.Field()
    content=scrapy.Field()

    cimage_urls=scrapy.Field()
    cimages=scrapy.Field()
    pass

 修改CnblogsSpider.py為:

import scrapy
from scrapy import Selector
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):
    name="cnblogs"
    allowd_domains=["cnblogs.com"]
    start_urls=["https://www.cnblogs.com/bai2018/"]
    def parse(self,response):
        papers=response.xpath(".//*[@class='day']")
        for paper in papers:
            url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()[0]
            title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
            time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
            content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
            
            item=MytestprojectItem(url=url,title=title,time=time,content=content)
            request=scrapy.Request(url=url, callback=self.parse_body)
            request.meta['item']=item

            yield request
        next_page=Selector(response).re(u'<a href="(\S*)">下一頁</a>')
        if next_page:
            yield scrapy.Request(url=next_page[0],callback=self.parse)
        pass
    
    def parse_body(self, response):
        item = response.meta['item']
        body = response.xpath(".//*[@class='postBody']")
        item['cimage_urls'] = body.xpath('.//img//@src').extract()
        yield item

啟動爬蟲

建立main函式,傳遞初始化資訊,匯入指定類。如:

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

from myTestProject.spiders.CnblogSpider import CnblogsSpider

if __name__=='__main__':
    process = CrawlerProcess(get_project_settings())
    process.crawl('cnblogs')
    process.start()

 

相關文章