Python爬蟲第十一課:Scrapy框架(2)——存儲數據

在這裏插入圖片描述
在Scrapy的整個架構中,引擎是可以說有着最高的權利,管理着調度器、下載器、爬蟲和數據管道四個重要的組成部分。

這四個組成部分都聽命於引擎,一絲不苟的執行引擎下發的命令。
在這裏插入圖片描述
本次,我們使用Scrapy爬取職友集的招聘信息,讓我們更加熟練的掌握Scrapy的用法。

一、明確目標

職友集可以通過索引的方式,搜索到全國上百家招聘網站的最新職位:https://www.jobui.com/rank/company/

我們要獲取排行榜中的公司名稱、招聘職位名稱、工作地點和招聘要求。

二、代碼實現

(1)創建項目

在命令行或終端中,cd到想要保存爬蟲的目錄下,輸入創建scrapy項目的命令:scrapy startproject class14(名稱可自定義)。

然後在蹦迪電腦的編譯器中打開這個scrapy項目,如下所示:
在這裏插入圖片描述

(2)定義items

在items.py文件中,定義Items:

import scrapy

# 定義一個繼承自scrapy.Item的Class14Item類
class Class14Item(scrapy.Item):
    # 定義公司名稱的數據屬性
    company = scrapy.Field()
    # 定義職位名稱的數據屬性
    position = scrapy.Field()
    # 定義工作地點的數據屬性
    address = scrapy.Field()
    # 定義招聘要求的數據屬性
    info = scrapy.Field()

(3)創建和編寫爬蟲文件

在spiders文件夾下創建爬蟲文件,我們將它命名爲Jobhui_Info。

import scrapy
import bs4
from ..items import Class14Item

# 定義爬蟲類Jobhui_Info
class Jobhui_Info(scrapy.Spider):
    # 定義爬蟲的名稱
    name = 'Jobhui_Info'
    # 定義允許爬蟲爬取網址的域名
    allowed_domains = ['www.jobhui.com']
    # 定義起始網址
    start_urls = ['https://www.jobhui.com/rank/company']

    def parse(self, response):
        # 使用beautifulsoup解析response
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        # 提取1-10的公司,用find_all提取<ul class_="textList flsty cfix">標籤
        ul_list = bs.find_all('div',class_='textlist flsty cfix')
        for ul in ul_list:
            a_list = ul.find_all('a')
            for a in a_list:
                # 提取出<a>標籤的href屬性的值,即公司id標識
                company_id = a['href']
                # 構造出包含公司名稱和招聘信息的網址鏈接的list
                url = 'https://www.jobhui.com{}jobs'.format(company_id)           

接下來,我們要獲取不同公司的招聘職位信息。

從這裏開始,就需要重新構造新的requests對象和定義新的方法處理response。

import scrapy
import bs4
from ..items import Class14Item

# 定義爬蟲類Jobhui_Info
class Jobhui_Info(scrapy.Spider):
    # 定義爬蟲的名稱
    name = 'Jobhui_Info'
    # 定義允許爬蟲爬取網址的域名
    allowed_domains = ['www.jobhui.com']
    # 定義起始網址
    start_urls = ['https://www.jobhui.com/rank/company']

    def parse(self, response):
        # 使用beautifulsoup解析response
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        # 提取1-10的公司,用find_all提取<ul class_="textList flsty cfix">標籤
        ul_list = bs.find_all('div',class_='textlist flsty cfix')
        for ul in ul_list:
            a_list = ul.find_all('a')
            for a in a_list:
                # 提取出<a>標籤的href屬性的值,即公司id標識
                company_id = a['href']
                # 構造出包含公司名稱和招聘信息的網址鏈接的list
                url = 'https://www.jobhui.com{}jobs'.format(company_id)
                # 用yield語句把構造好的request對象傳遞給引擎。
                # 用scrapy.Request構造request對象。callback參數設置調用parse_Jobhui_Info方法。
                yield scrapy.Request(url, callback=self.parse_Jobhui_Info)

    # 定義新的處理response的方法parse_Jobhui_Info
    def parse_Jobhui_Info(self,response):
        # 解析源碼數據
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        # 獲取公司名稱
        comany = bs.find(class_='company-banner-name')
        # 獲取招聘信息的列表
        datas = bs.find_all('div', class_='job-simple-content')
        # 遍歷datas
        for data in datas:
            # 實例化Class14Item類
            item = Class14Item()
            # 將公司名稱放回Class14Item類的company屬性
            item['company'] = comany
            # 提取職位名稱,並放回Class14Item類的position屬性
            item['position'] = data.find_all('div', class_="job-segmetation")[0].find('h3').text
            # 提取出工作地點,並把這個數據放回Class14Item類的address屬性裏
            item['address'] = data.find_all('div', class_="job-segmetation")[1].find_all('span')[0].text
            # 提取出招聘要求,並把這個數據放回Class14Item類的detail屬性裏
            item['info'] = data.find_all('div', class_="job-segmetation")[1].find_all('span')[1].text

            # 用yield語句把item傳遞給引擎
            yield item

其中的部分代碼解釋一下:
scrapy.Request是構造requests對象的類。url是我們往requests對象裏傳入的每家公司招聘信息網址的參數。

  • callback的中文意思是回調。self.parse_Jobhui_Info是我們新定義的parse_Jobhui_Info方法。往requests對象裏傳入callback=self.parse_GetJobInfo這個參數後,引擎就能知道response要前往的下一站,是用parse_Jobhui_Info()方法來解析傳入的新參數。
  • yield的作用就是把這個構造好的requests對象傳遞給引擎。

(4)存儲文件

Scrapy可以支持把數據存儲成csv文件或者Excel文件:

  • 存儲成csv文件的方法比較簡單,只需在settings.py文件裏,添加如下的代碼即可:
FEED_URI = '%(Jobhui_Info)s.csv'
FEED_FORMAT = 'CSV'
FEED_EXPORT_ENCODING = 'ansi'
  • FEED_URI是導出文件的路徑。’%(Jobhui_Info)s.csv’,是把CSV文件放到與settings.py文件同級的文件夾內。
  • FEED_FORMAT 是導出數據格式,寫CSV就能得到CSV格式。
  • FEED_EXPORT_ENCODING 是導出文件編碼,ansi是一種在windows上的編碼格式,你也可以把它變成utf-8用在mac電腦上。

需要注意:在最新的scrapy版本2.1.0不支持這種方式。需要降級到1.8.0版本才能存儲進csv文件中。

  • 存儲成Excel文件,相對複雜一些。實現步驟如下:
  1. 先在setting.py裏設置啓用ITEM_PIPELINES。取消掉ITEM_PIPLINES的註釋即可。
# Configure item pipelines

# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html

ITEM_PIPELINES = {

   'class14.pipelines.Class14Pipeline': 300,

}
  1. 在piplines.py文件中,編輯代碼。依然是使用openpyxy來實現對數據的保存。
import openpyxl

# 定義一個 Class14Pipeline
class Class14Pipeline(object):
    # 初始化函數,當類實例化時該方法自動啓動
    def __init__(self):
        # 創建工作簿
        self.wb = openpyxl.Workbook()
        # 定位工作表
        self.ws = self.wb.active
        # 使用append函數往表格中添加表頭
        self.ws.append(['公司','職位','地址','招聘信息'])

    # process_item是默認的處理item的方法,就像parse是默認處理response的方法
    def process_item(self,item,spider):
        # 把公司名稱、職位名稱、工作地點和招聘要求都寫成列表的形式,賦值給line
        line = [item['company'],item['position'],item['address'],item['info']]
        # 用append函數把公司名稱、職位名稱、工作地點和招聘要求的數據都添加進表格
        self.ws.append(line)
        # 將item給回引擎,如果後面還有這個item需要經過的itempipeline,引擎會自己調度
        return item

    # close_spider是當爬蟲結束運行時,這個方法就會執行
    def close_spider(self, spider):
        # 保存文件
        self.wb.save('Jobhui_Info.xlsx')
        # 關閉文件
        self.wb.close()

(5)修改設置

在settings.py文件裏添加請求頭,以及把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

同時,我們要將#DOWNLOAD_DELAY = 3這行取消註釋,同時對DOWNLOAD_DELAY這個參數的值進行修改。

DOWNLOAD_DELAY的意思是下載延遲,這個參數的作用是控制爬蟲的速度。3秒對於這個項目來說太慢了,我們要把下載延遲的時間改成0.5秒。

# 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 = 0.5

三、練習

  1. 使用scrapy爬取豆瓣圖TOP250前2頁的書籍的短評數據(包括書名、評論ID、短評內容),並存儲成Excel文件。
    (1)創建項目
    在cmd窗口,cd到所在文件夾:“scrapy startproject Doubanbook_Comments"
    (2)定義Item
    在Items.py文件中,輸入下列代碼:
import scrapy

class DoubanbookCommentsItem(scrapy.Item):
    # 定義書籍名稱的數據屬性
    name = scrapy.Field()
    # 定義評論ID的數據屬性
    commentID = scrapy.Field()
    # 定義短評內容點的數據屬性
    comment = scrapy.Field()

(3)創建和編寫爬蟲文件
在spiders文件夾下,新建文件Doubanbook_Comments.py。並編寫代碼如下:

import scrapy
import bs4
from ..items import DoubanbookCommentsItem

# 定義一個爬蟲類doubanbookComments
class Doubanbook_Comments(scrapy.Spider):
    # 定義爬蟲名字
    name = 'Doubanbook_Comments'
    # 定義允許爬蟲爬取的網址
    allowed_domains = ['book.douban.com']
    # 定義起始網址
    start_urls = []
    # 根據豆瓣圖書的url規律,取前3頁的Url,並添加進起始網址中(只取第一頁的書籍)
    for i in range(1):
        url = 'https://book.douban.com/top250?start={}'.format(i*25)
        start_urls.append(url)

    # 定義parse方法,獲取每本書籍詳情頁的鏈接
    def parse(self, response):
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        url_list = bs.find_all('div',class_="pl2")

        for url in url_list:
            # <a>標籤的值就是書籍詳情頁的鏈接
            book_url = url.find('a')['href']
            # 爲不給網站造成負擔,僅抓取第一頁的短評內容
            for i in range(1,2):
                comment_url = '{}comments/new?p={}'.format(book_url,i)
                # 用yield語句把構造好的request對象傳遞給引擎
                yield scrapy.Request(comment_url,callback=self.parse_Get_bookomments)

    # 定義新的處理方法parse_Get_bookcomments
    def parse_Get_bookcomments(self, response):
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        # 提取到書名
        name = bs.find('h1').text.replace(' 短評','')
        # 提取到書籍評論列表
        comment_list = bs.find_all('div',class_='comment')
        # 遍歷列表
        for comment in comment_list:
            # 實例化DoubanbookCommentsItem類
            item = DoubanbookCommentsItem()
            # 將書籍名稱放回DoubanbookCommentsItem類中
            item['name'] = name
            # 將評論人名稱放回DoubanbookCommentsItem類
            item['commentID'] = comment.find('span',class_='comment-info').find('a').text
            item['comment'] = comment.find('span',class_='short').text

            # 使用yield語句把item傳遞給引擎
            yield item

(4)存儲文件

  1. 在setting.py文件中,將ITEM_PIPELINES的註釋去掉。
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'Doubanbook_Comments.pipelines.DoubanbookCommentsPipeline': 300,
}
  1. 在pipelines.py文件中,使用openpyxy來實現對數據的存儲。
import openpyxl


# 定義一個DoubanbookCommentsPipeline類,負責處理item
class DoubanbookCommentsPipeline(object):
    # 初始化函數,當類實例化時,自動啓動該方法
    def __init__(self):
        # 創建工作簿
        self.wb = openpyxl.Workbook()
        # 創建工作表
        self.ws = self.wb.active
        # 添加表頭
        self.ws.append(['書籍名稱', '評論人', '評論內容'])

    # process_item是默認的處理item的方法,就像parse是默認處理response的方法
    def process_item(self, item, spider):
        # 將書籍名稱、評論人、評論內容賦值
        line = [item['name'], item['commentID'], item['comment']]
        # 將對應的數據添加進表格中
        self.ws.append(line)

        return item

    # close_spider是當爬蟲結束運行時,這個方法就會執行
    def close_spider(self, spider):
        # 保存文件
        self.wb.save('douban_bookcomments.xlsx')
        # 關閉文件
        self.wb.close()

(5)修改設置
在settings.py文件中,添加請求頭,把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}


# Obey robots.txt rules
ROBOTSTXT_OBEY = False

同時修改一下下載延遲時間,調整到0.5秒

# 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 = 0.5
  1. 使用Scrapy,爬取噹噹網2018年圖書銷售榜單前3頁的數據,包括排名、圖書名、作者、出版社、書的原價、價格折扣、折扣價、評價數量。
    網址: http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-year-2019-0-1-1

實現步驟

1. 創建項目

在CMD中,cd到項目所在文件夾,創建項目,命名爲DDbook。

scrapy startproject DDbook

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tV3ajZXJ-1592558823816)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3560fb1c-7733-4faa-9577-656c26190507/Untitled.png)]

2. 定義items

在items.py文件中,定義items。

import scrapy

class DdbookItem(scrapy.Item):
		# 定義書籍排名的數據屬性
    num = scrapy.Field()
    # 定義書籍名稱的數據屬性
    name = scrapy.Field()
    # 定義作者的數據屬性
    author = scrapy.Field()
    # 定義出版社的數據屬性
    publish = scrapy.Field()
    # 定義書原價的數據屬性
    price = scrapy.Field()
    # 定義書籍折扣的數據屬性
    discount = scrapy.Field()
    # 定義折扣價的數據屬性
    dis_price = scrapy.Field()
    # 定義評價數量的數據屬性
    rating_num = scrapy.Field()

3. 創建和編寫爬蟲文件

在spiders文件夾下,創建DDbook.py文件,在其中編寫爬蟲代碼:

import scrapy
import bs4
from ..items import DDbookItem

# 定義爬蟲類DDbook,繼承自scrapy.Spider
class DDbook(scrapy.Spider):
    # 定義爬蟲的名稱
    name = 'DDbook'
    # 定義允許爬蟲爬取網址的域名
    allowed_domains = ['http://bang.dangdang.com']
    # 定義起始網頁
    start_urls = []
    for i in range(1, 4):
        url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-year-2019-0-1-{}'.format(i)
        start_urls.append(url)

    def parse(self, response):
        # 使用bs4解析數據
        bs = bs4.BeautifulSoup(response.text, 'html.parser')
        # 提取所有書籍的列表
        li_list = bs.find('ul', class_='bang_list clearfix bang_list_mode').find_all('li')
        # 遍歷列表
        for book in li_list:
            # 實例化DDbook對象
            item = DDbookItem()
            # 將書籍排名放回DDbook的num屬性
            item['num'] = book.find_all('div')[0].text.replace('.', '')
            # 將書籍名稱放回DDbook類的name屬性
            item['name'] = book.find('div', class_='name').find('a')['title']
            # 將作者放回DDbook類的author屬性
						# 部分書籍沒有作者,使用異常捕捉
						try:
                item['author'] = book.find_all('div', class_='publisher_info')[0].find('a').text
            
            except:
                item['author'] = None

            # 將出版社放回DDbook類的publish屬性
            item['publish'] = book.find_all('div', class_='publisher_info')[1].find('a').text
            # 將書籍價格放回DDbook類的price屬性
            item['price'] = book.find('span', class_='price_r').text
            # 將折扣放回DDbook的discount屬性
            item['discount'] = book.find('span', class_='price_s').text
            # 將折扣價放回DDbook的dis_price屬性
            item['dis_price'] = book.find('span', class_='price_n').text
            # 將評價數量放回到DDbook的rating_num屬性
            item['rating_num'] = book.find('div', class_='star').find('a').text

            # yield語句把item傳遞給引擎
            yield item

4. 存儲文件

採用CSV格式進行存儲,在settings.py中輸入如下代碼:

FEED_URI = '%(name)s.csv'
FEED_FORMAT = 'CSV'
FEED_EXPORT_ENCODING = 'ansi'

需要注意:在最新的scrapy版本2.1.0不支持這種方式。需要降級到1.8.0版本才能存儲進csv文件中。

5. 修改設置

在settings.py文件裏添加請求頭,以及把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

同時修改一下下載延遲時間,調整到0.5秒。

# 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 = 0.5

6. 運行scrapy

在與scrapy.cfg文件同級中,建立main.py文件。輸入以下代碼,接着運行即可。

from scrapy import cmdline

cmdline.execute(['scrapy','crawl','DDbook'])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章