python爬蟲之Scrapy的使用步驟
- 首先講講教程的例子,還是以百度股票爲例子進行講解
Scrapy的使用步驟
- 建立工程和Spider模版
- 編寫Spider
- 編寫ITEM Pipelines
前請回顧
- 首先回顧一下爬取股票數據的相關的知識點和思路
- 基本思路:從東方財富網獲取所有股票的代碼,然後在組成新的百度網網頁,跳轉到對應的列表中爬取對應的信息
- 先看看,東方財富的網頁,篩選的正則表達式:r’[zh|sh]\d{6}’
-
再看看單個股票網頁的網址,只需要在對應的網頁加上對應的股票編碼就可以獲得
-
最後再看看但個網頁的股票的具體的價格信息,分別在對應的dd和tt標籤中,名稱在屬性爲“bets—name”的屬性中
具體編寫
第一步、建立工程和Spider模版
- 在控制檯輸入如下指令
- 創建對應的scrapy工程: scrapy startproject BaiduStocks
- 切換到創建的工程目錄下:cd BaiduStocks
- 創建相關的爬蟲:scrapy genspider stocks baidu.com
第二步、編寫對應的Spider工具
- 配置stocks.py文件,確定你需要爬取的具體的信息
- 修改對返回頁面的處理
- 修改對新增的URL爬取請求的處理
首先打開如下位置的文件
分析:
根據功能請求,總共爬取兩類網站,所以最基本的得寫針對兩類網站的爬取代碼
- 部分一:爬取東方財富網的所有股票的信息地址
- css().extract()是返回對應的所有的標籤內部的值,關於css用法,詳見 https://www.jianshu.com/p/278a4ca6d0c1 覺得還不錯
- yield生成器,生成的是request對象,專門給downloader進行處理
- callback指明對應的返回response對象,處理的函數
def parse(self, response):
for href in response.css('a::attr(href)').extract():
# 提取其中所有的a標籤,並獲取其中href連接
try:
stock = re.findall(r'[s][hz]\d{6}',href)[0]
# 通過正則表達式,獲得相關的股票的代碼
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
# 生成百度股票的html網頁
yield scrapy.Request(url,callback=self.parse_stock)
# 根據生成的網頁在生成相關的request對象,以供downloader進行下載
# callback是指定相應的函數類型
except:
continue
- 部分二:爬取百度股票網的單個網頁的具體的信息
- 指明當前函數的生成對象,非requests就是item,指明字典類默認就是給ITEM pipeline進行處理了
- stockInfo = response.css(’.stock-bets’),找到對應的具有stock-bets的屬性的標籤,返回的是selector對象
- name = stockInfo.css(’.bet-name’).extract()[0],借用上面的selector對象,然後返回所有的具有bet-name屬性的標籤的值組成的列表
- keyList= stockInfo.css(‘dt’).extract()
valueList = stockInfo.css(‘dd’).extract(),就分別返回的是dt和dd標籤的值組成的列表 - 字典的update函數有些忘記:
代碼如下:
# 定義指定的處理的信息
def parse_stock(self,response):
infoDict = {}
# 返回的信息是交給itempipeline進行處理的,所以用字典的信息進行存儲
stockInfo = response.css('.stock-bets')
name = stockInfo.css('.bet-name').extract()[0]
keyList= stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
for i in range(len(keyList)):
key = re.findall(r'>.*</dt',keyList[i])[0]
try:
val = re.findall(r'\d+\.?.*</dd>',valueList[i])[0]
except:
val = '--'
infoDict[key] = val
# 一個字典條目,增加一個股票名稱
infoDict['股票名稱'] = re.findall('\s.*\(',name)[0].split()[0] + re.findall('\>.*\<',name)[0]
yield infoDict
# 將生成的item給itemPipeLine進行處理
總的代碼
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = 'stocks'
start_urls = ['http://quote.eastmoney.com/stocklist.html']
# 是先從東方財富網獲得每個股票的代碼,然後生成和百度股票相關的url連接
def parse(self, response):
for href in response.css('a::attr(href)').extract():
# 提取其中所有的a標籤,並獲取其中href連接
try:
stock = re.findall(r'[s][hz]\d{6}',href)[0]
# 通過正則表達式,獲得相關的股票的代碼
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
# 生成百度股票的html網頁
yield scrapy.Request(url,callback=self.parse_stock)
# 根據生成的網頁在生成相關的request對象,以供downloader進行下載
# callback是指定相應的函數類型
except:
continue
# 定義指定的處理的信息
def parse_stock(self,response):
infoDict = {}
# 返回的信息是交給itempipeline進行處理的,所以用字典的信息進行存儲
stockInfo = response.css('.stock-bets')
name = stockInfo.css('.bet-name').extract()[0]
keyList= stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
for i in range(len(keyList)):
key = re.findall(r'>.*</dt',keyList[i])[0]
try:
val = re.findall(r'\d+\.?.*</dd>',valueList[i])[0]
except:
val = '--'
infoDict[key] = val
# 更新股票的名稱
infoDict.update({
'股票名稱':re.findall('\s.*\(',name)[0].split()[0] + \
re.findall('\>.*\<',name)[0]
})
yield infoDict
# 將生成的item給itemPipeLine進行處理
第三步、編寫ITEM pipelines
- 配置匹配pipelines.py文件
- 定義對爬取項的處理類
- 在settings中配置相關的ITEM_PIPELINES選項,確保scrapy可以自動找到對應的item處理類
代碼如下:
- 主要有三個方法,傳入相關的爬蟲時,自動打開對應的寫入的文件,結束爬蟲時,自動關閉文件,以及對文件的具體寫入
- 分別是open_spider,close_spider和process_item
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# 下面的每一個類都是對一個item類進行處理的過程
class BaidustocksPipeline:
def process_item(self, item, spider):
return item
# 定義一個專門用來處理的infoDict的方法
class BaidustocksInfoPipeline(object):
def open_spider(self,spider):
self.f = open('BaiduStocksInfo.txt','w')
def close_spider(self,spider):
self.f.close()
# 最核心的,對每一個item的處理方法
def process_item(self,item,spider):
try:
line = str(dict(item)) + '\n'
self.f.write(line)
except:
pass
return item
# 如果需要別的函數也可以操作對應的item,就需要返回item對象
這一步千萬別忘記,要給系統看的說明書中加上你寫的pipeline類
總結
- 雖然很想繼續做下去,學下去,但是,真的很煩,作業好多,又要開始複習了
- 這個教程應該沒有將scrapy框架作爲重點,我應該再繼續學習對應的框架內容,好在以後的內容中用於實戰