Scrapy糗事百科爬蟲實戰代碼分析

Scrapy糗事百科爬蟲實戰代碼分析

視頻教學網址:【python爬蟲_從入門到精通(高級篇)】scrapy框架、反爬、分佈式爬蟲

一、Scrapy糗事百科之爬取單頁數據並保存

具體的創建方法可以參照上一篇文章Python最火爬蟲框架Scrapy入門與實踐
創建的目錄結構如下:
在這裏插入圖片描述

在qsbk_spider.py文件中,response是一個’scrapy.http.response.html.HtmlResponse’對象.可以執行’xpath’和’css’語法來提取數據。

# -*- coding: utf-8 -*-
import scrapy
from qsbk.items import QsbkItem


class QsbkSpiderSpider(scrapy.Spider):
    name = 'qsbk_spider'
    allowed_domains = ['qiushibaike.com']
    start_urls = ['https://www.qiushibaike.com/text/page/1/']

    def parse(self, response):
        # SelectorList
        duanzidivs =  response.xpath("//div[@class='col1 old-style-col1']/div")
        # 遍歷div
        for duanzidiv in duanzidivs:
            # Selector-->Unicode
            author =  duanzidiv.xpath(".//a/h2/text()").get().strip()
            content = duanzidiv.xpath(".//div[@class='content']//text()").getall()
            content = " ".join(content).strip()
            # 提取出來的數據,是一個’Selector’或者是一個’SelectorList’對象。如果想要獲取其中的字符串,那麼應該執行’getall’或是’get’方法
            # getall方法:獲取Selector中的所有文本,返回的是一個列表。get方法:是獲取selector中的第一個文本,返回的是str類型.

            item = QsbkItem(author=author,content=content)
			
			#如果數據解析回來,要傳給pipline處理.那麼可以使用’yield’來返.或是可以收集到所有的item,最後統一使用return返回.
            yield item

在itmes.py文件中,用來存放爬蟲爬取下來的數據類型,裏面的數據與qsbk_spider.py 定義的 一 一對應。

import scrapy
# item:建議在item.py中定義好模型.以後就不要使用字典了.在最後將數據變成字典就行了
class QsbkItem(scrapy.Item):
    author = scrapy.Field()
    content = scrapy.Field()

在piplines文件中,用來將items的模型存儲到本地磁盤中;
pipeline:這個是專門用來保存數據地.其中三個方法是會經常用到的
①open_spider(self,spider):當爬蟲被打開的時候就會被調用
②process_item(self,item,spider):當爬蟲有item傳過來的時候就會被調用
③close_spider(self,spider):當爬蟲關閉的時候會被調用

要激活piplilne , 應該在settings.py中設置ITEM_PIPELINES將其激活.

import json

class QsbkPipeline(object):
    def __init__(self):
        self.fp = open("duanzi.json",'w',encoding="utf-8") # 創建一個導入的對象

    def open_spider(self,spider):
        print("爬蟲開始了。。")

    def process_item(self, item, spider):
        # 將item轉換爲字典,再將字典轉換爲json ;item是爬蟲返回的數據
        item_json = json.dumps(dict(item),ensure_ascii=False) 
        # json字符串寫入文件當中
        self.fp.write(item_json+'\n')
        return item

    def close_spider(self,spider):
        self.fp.close()
        print("爬蟲結束了。。")

settings.py: 本爬蟲的一些配置信息(比如請求頭、多久發送一次、ip代理池等等),需要將下面的註釋去掉。

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36 SLBrowser/6.0.1.4221'
}

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'qsbk.pipelines.QsbkPipeline': 300, #值越小優先級越高;當設置多個爬蟲時,可以參考此值。
}

由於每一次在命令端調試比較麻煩,可以在qsbk文件的根目錄創建start.py文件進行調試。

from scrapy import cmdline
# 調式
cmdline.execute("scrapy crawl qsbk_spider".split())
# cmdline.execute(['scrapy', 'crawl', 'qsbk_spider'])

二、Scrapy糗事百科之優化數據存儲方式

在pipelines.py文件裏保存json數據的時候,可以使用這兩個類,讓操作更加簡單。
①JsonItemExporter:這個是每次把數據添加到內存中.最後統一寫入到磁盤中.
好處就是存儲的數據是一個滿足json規則的數據.
壞處就是如果數據量比較大,那麼比較消耗內存

from scrapy.exporters import JsonItemExporter
class QsbkPipeline(object):
    def __init__(self):
        # 二進制打開文件,因爲JsonItemExporter是以二進制寫入寫入的
        self.fp = open("duanzi.json",'wb')
        self.exporter = JsonItemExporter(self.fp,ensure_ascii=False,encoding="utf-8")
        # 開始導入
        self.exporter.start_exporting()

    def open_spider(self,spider):
        print("爬蟲開始了。。")

    def process_item(self, item, spider):
        # 先把傳進來的字典塞到一個列表當中
        self.exporter.export_item(item)
        return item

    def close_spider(self,spider):
        # 完成導入
        self.exporter.finish_exporting() # 再統一寫道json文件中

json文件存儲一行數據:

[{"author": "山鷹寂寞飛", "content": "那年那人那山第三十二章:錢去樓空 紅軍很驚訝的問:“怎麼了?是怪我昨天沒來接你嗎?”秀芬面無表情,眼角淚珠往下飛速滾淌着。   紅軍湊上前,蹲下握住秀芬的手道:“好了,我知道錯了,下次不管再晚,哪怕騎車也過來接你,好不好?”    秀芬觸電一般用力拽回自己的手,歇斯底里大叫一句:“你走啊!我不想再看到你!”    紅軍嚇了一跳,見秀芬如此激動,好像真想分手,有點莫名其妙,他盯了秀芬一會,眼見她側臉昂頭,只流淚不再說話,態度相當堅決,思忖一會問:“爲什麼?總得給我個理由吧?是…因爲我沒\n…\n \n\n 查看全文"}]......

②JsonLinesItemExporter:這個是每次調用export_item的時候就吧這個item存儲到硬盤當中.
壞處是每一個字典是一行,整個文件不是一個滿足json格式的文件.
好處就是每次處理數據的時候就直接存儲到硬盤當中,這樣不會消耗內存,數據也比較安全.

from scrapy.exporters import JsonLinesItemExporter
class QsbkPipeline(object):
    def __init__(self):
        # 二進制打開文件,因爲JsonItemExporter是以二進制寫入寫入的
        self.fp = open("duanzi.json",'wb')
        self.exporter = JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding="utf-8")

    def open_spider(self,spider):
        print("爬蟲開始了。。")

    def process_item(self, item, spider):
        # 先把傳進來的字典塞到一個列表當中
        self.exporter.export_item(item)
        return item

    def close_spider(self,spider):
        self.fp.close()
        print("爬蟲結束了。。")

輸出結果:一個字典一行的存儲:

{"author": "山鷹寂寞飛", "content": "那年那人那山第三十三章:煉獄化療 傳說中的化療很快來到,秀芬和紅軍以爲是什麼工程浩大驚天動地的療法,沒成想也就是幾瓶藥水輸進身體。    然而他們都小瞧了這幾瓶藥水的威力,剛掛上沒一會,楚建國開始噁心,說胃裏火燒火燎像有硫酸在腐蝕,不停的乾嘔着,後來實在憋持不住,讓秀芬趕緊拿來垃圾桶,他側倒在牀沿翻江倒海的抽搐着身子,一陣又一陣吐得眼淚直流。    早上吃的東西全都吐了個乾淨,順着嘴角又一佝僂一佝僂嘔出黃疸水,偌大的一個壯漢,竟然像個孩子似的,吐的哭出了聲音。    秀芬很害怕,去找值班醫生,\n…\n \n\n 查看全文"}
{"author": "五少爺的刀", "content": "中午在食堂吃午飯的時候,剛好和廠長坐在一起,爲了活躍氣氛,我就講了兩個笑話。 廠長果然被我逗笑了,噗~的一聲,把他剛扒進嘴裏的飯全噴在我碗裏了。。。 大家都放下了碗筷,扭頭看我。 就在我在考慮是不是不要了的時間,廠長帶的二哈跳起來把我的飯吃了!…… 謝天謝地啊,謝天謝地!!!……我站起來,朝着二哈,一躬到地。。。"}
{"author": "精靈不次飯~", "content": "穿了條新裙子,照鏡子覺得特別好看。我腦子一抽就發視頻給在玩遊戲的老公,問他好看不,還跟他賣個萌做了個鬼臉。 現在我很想把他踹出家門!!這貨不停的追問我“你直接喊我來看不就行了嗎?”“我在家呢,你發視頻幹啥?”“你是不是發錯人了?” “你本來打算髮給誰的?”"}
.......

三、Scrapy糗事百科之抓取多個頁面

修改qsbk_spider.py,分析"下一頁"按鈕的標籤結構
在這裏插入圖片描述

# -*- coding: utf-8 -*-
import scrapy
from qsbk.items import QsbkItem

class QsbkSpiderSpider(scrapy.Spider):
    name = 'qsbk_spider'
    allowed_domains = ['qiushibaike.com']
    start_urls = ['https://www.qiushibaike.com/text/page/1/']
    base_domain = "https://www.qiushibaike.com"

    def parse(self, response):
        # SelectorList
        duanzidivs =  response.xpath("//div[@class='col1 old-style-col1']/div")
        # 遍歷div
        for duanzidiv in duanzidivs:
            # Selector-->
            author =  duanzidiv.xpath(".//a/h2/text()").get().strip()
            content = duanzidiv.xpath(".//div[@class='content']//text()").getall()
            content = " ".join(content).strip()

            item = QsbkItem(author=author,content=content)

            yield item

        next_url = response.xpath("//ul[@class='pagination']/li[last()]/a/@href").get()
        if not next_url:
            return
        else:
            yield scrapy.Request(self.base_domain+next_url,callback=self.parse)
            # 返回當前的請求

在setting文件中,找到下面的註釋掉,可以調成一秒獲取一次數據

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章