天天看點

scrapy爬蟲架構(四):scrapy中 yield使用詳解

開始前的準備工作:

MySQL下載下傳:點我

python MySQL驅動下載下傳:pymysql(pyMySql,直接用pip方式安裝)

全部安裝好之後,我們來熟悉一下pymysql子產品

import pymysql

#建立連結對象
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python')
#建立遊标 遊标用來進行查詢,修改等操作
cursor = connection.cursor()

#定義sql語句 這裡的sql文法根據使用的資料庫不同會有一些小差别
sql = "SELECT * FROM python.text_info where text_title='test'"

#執行sql語句 傳回受到影響的行數
cursor.execute(sql)

#擷取sql語句執行後的傳回資料 預設傳回的資料類型為元組
#擷取所有傳回
r = cursor.fetchall()
#擷取一個傳回
r = cursor.fetchone()
#擷取至多三個傳回 不足三個時傳回所有
r = cursor.fetchmany(3)
#其他的fetch方法可自行百度

#将傳回資料類型改為字典
cursor = connection.cursor(cursor=pymysql.cursors.DictCursor)
#或者在建立連接配接對象時指定傳回資料類型為字典 建議把傳回類型修改為字典類型
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python', cursorclass=pymysql.cursors.DictCursor)

#儲存所做的修改 在連接配接關閉之前,如果你沒有調用下面的語句
#那麼,你之前的所有修改将不會被儲存
connection.commit()

#關閉遊标
cursor.close()
#關閉連接配接
connection.close()           

複制

一、确定items

我們要爬取的網站是:http://m.50zw.la

要爬取的是小說的資訊,如圖:

scrapy爬蟲架構(四):scrapy中 yield使用詳解

是以items.py檔案如下:

import scrapy


class TextInfoItem(scrapy.Item):
    # name = scrapy.Field()
    text_name = scrapy.Field()
    text_author = scrapy.Field()
    text_type = scrapy.Field()
    text_status = scrapy.Field()
    text_latest = scrapy.Field()
    text_intro = scrapy.Field()           

複制

最後資訊是要儲存到資料庫裡的,是以我們還得建立一個資料庫表。

  • 第一步:在開始菜單裡找到MySQL Workbench,輕按兩下打開。MySQL Workbench是MySQL自帶的一個可視化管理工具
  • 第二步:在 MySQL Workbench裡連接配接資料庫,并建立一個資料庫 python,然後再在剛剛建立的資料庫裡建立一個表 text_info
  • 第三步:在 text_info表裡逐一添加 text_name,text_author 等屬性,類型全部設定為 varchar,大小除了 text_intro是 1000外,其他的全部設定為 50

MySQL的使用就不詳細講了。如果遇到問題,歡迎評論留言。

二、爬取資訊

為了簡單,我們隻爬取 50zw網站下的玄幻分類的小說資訊。

細節前面已經講過了,這裡不再多講,有不懂的可以去看前面的幾篇文章。

廢話不多說,直接上代碼:

import scrapy
from text_info.items import TextInfoItem

class A50zwSpider(scrapy.Spider):
    name = '50zw'
    allowed_domains = ['m.50zw.la']
    start_urls = ['http://m.50zw.la/wapsort/1_1.html']

    #主站連結 用來拼接
    base_site = 'http://m.50zw.la'

    def parse(self, response):
        book_urls = response.xpath('//table[@class="list-item"]//a/@href').extract()

        for book_url in book_urls:
            url = self.base_site + book_url
            yield scrapy.Request(url, callback=self.getInfo)

        #擷取下一頁
        next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一頁")]/@href').extract()[0]
        yield scrapy.Request(next_page_url, callback=self.parse)

    def getInfo(self, response):
        item = TextInfoItem()

        #提取資訊
        item['text_id'] = response.url.split('_')[1].replace('/', '')
        item['text_name'] = response.xpath('//table[1]//p/strong/text()').extract()[0]
        item['text_author'] = response.xpath('//table[1]//p/a/text()').extract()[0]
        item['text_type'] = response.xpath('//table[1]//p/a/text()').extract()[1]
        item['text_status'] = response.xpath('//table[1]//p/text()').extract()[2][3:]
        item['text_latest'] = response.xpath('//table[1]//p[5]/text()').extract()[0][3:]
        item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]

        yield item           

複制

這裡我們通過

yield

來發起一個請求,并通過

callback

參數為這個請求添加回調函數,在請求完成之後會将響應作為參數傳遞給回調函數。

scrapy架構會根據

yield

傳回的執行個體類型來執行不同的操作,如果是

scrapy.Request

對象,scrapy架構會去獲得該對象指向的連結并在請求完成後調用該對象的回調函數。

如果是

scrapy.Item

對象,scrapy架構會将這個對象傳遞給 pipelines.py做進一步處理。

這裡我們有三個地方使用了

yield

,第一個地方是:

for book_url in book_urls:
        url = self.base_site + book_url
        yield scrapy.Request(url, callback=self.getInfo)           

複制

這裡我們在循環裡不斷提取小說詳細頁面的連結,并通過

yield

來發起請求,并且還将函數

getInfo

作為回調函數來從響應中提取所需的資料。

第二個地方是:

#擷取下一頁
next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一頁")]/@href').extract()[0]
yield scrapy.Request(next_page_url, callback=self.parse)           

複制

這裡是在爬取完一頁的資訊後,我們在目前頁面擷取到了下一頁的連結,然後通過

yield

發起請求,并且将

parse

自己作為回調函數來處理下一頁的響應。

這有點像遞歸,不過遞歸是函數自己調用自己,這裡看起來好像是

parse

調用了自己,但實際上

parse

是由 scrapy架構在獲得響應後調用的。

最後一處使用了

yield

的地方在

getInfo

函數裡:

def getInfo(self, response):
        item = TextInfoItem()
        
        ... ...
        
        item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]
        yield item           

複制

這裡我們通過

yield

傳回的不是

Request

對象,而是一個

TextInfoItem

對象。

scrap有架構獲得這個對象之後,會将這個對象傳遞給 pipelines.py來做進一步處理。

我們将在 pipelines.py裡将傳遞過來的

scrapy.Item

對象儲存到資料庫裡去。

三、将資訊插入資料庫

python對資料庫的操作很簡單,我們簡單了解一下步驟:

  1. 建立資料庫連接配接
  2. 建立操作遊标
  3. 寫sql語句
  4. 執行sql語句
  5. 如果執行的是查詢語句,則用fetch語句擷取查詢結果
  6. 如果執行的是插入、删除等對資料庫造成了影響的sql語句,還需要執行commit儲存修改

貼上代碼:

import pymysql

class TextInfoPipeline(object):
    def __init__(self):
        #建立資料庫連接配接
        self.connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python',charset='utf8')
        #建立操作遊标
        self.cursor = self.connection.cursor()

    def process_item(self, item, spider):
        #定義sql語句
        sql = "INSERT INTO `python`.`text_info` (`text_id`, `text_name`, `text_author`, `text_type`, `text_status`, `text_latest`, `text_intro`) VALUES ('"+item['text_id']+"', '"+item['text_name']+"', '"+item['text_author']+"', '"+item['text_type']+"', '"+item['text_status']+"', '"+item['text_latest']+"', '"+item['text_intro']+"');"
        
        #執行sql語句
        self.cursor.execute(sql)
        #儲存修改
        self.connection.commit()

        return item

    def __del__(self):
        #關閉操作遊标
        self.cursor.close()
        #關閉資料庫連接配接
        self.connection.close()           

複制

寫在最後:

  1. 代碼敲好後不要忘記在settings裡開啟pipelines
  2. pymsql連接配接時預設的編碼是latin-1,是以在建立資料庫連接配接時會增加參數charset來修改編碼,要修改為utf-8的話得用charset=’utf8‘,而不是charset=’utf-8‘
  3. 這個網站有些問題,會時不時報404錯誤,是以在爬的過程中會報list index out of range,這是因為得到了錯誤的網頁,xpath找不到對應得路徑傳回了空清單。這是正常現象,并不是代碼出問題了(當然,如果頻繁報錯最好是檢查一下代碼)

貼一張成功後的圖檔:

scrapy爬蟲架構(四):scrapy中 yield使用詳解

最後的最後,覺得我寫的不錯的話記得關注我哦。