python爬蟲 之 scrapy框架採集2000期彩票資料

無惡不作傑尼龜發表於2020-12-02

python爬蟲 之 scrapy框架採集2000期彩票資料

最近學習一下資料分析,需要大量的資料,不知道搞啥好就用scrapy框架爬2000期的彩票雙色球,看看哪個號碼出現的機率大一些。
第一步:

  1. 在終端切換到想要新建爬蟲檔案的目錄下利用 cd XXXX 進行切換 在這裡插入圖片描述

  2. 輸入scrapy startproject 檔名 ,並利用cd 檔名 切換到新建目錄!在這裡插入圖片描述
    我這裡新建了一個專案叫gansha 這裡成功了就可以看到提示輸入cd gansha 進入到專案中

  3. 輸入scrapy genspider 爬蟲名 www.XXXXX.com 建立一個爬蟲檔案,後面的網址可以隨便寫到時候進入爬蟲檔案裡面可以改。 我這裡建立了一個叫ganshane的爬蟲檔案。在這裡插入圖片描述
    看到這個就說明已經建立好了。我們可以在目錄裡面看到在這裡插入圖片描述
    這裡 gansha 是專案名 裡面包含

    1. spiders (裡面包含使用者自己寫的爬蟲程式碼,用的最多),
    2. int.py (基本上用不著 不管),
    3. items.py (items程式碼模組,持久化儲存用的),
    4. middlewares.py (中介軟體,作用很多UA偽裝,代理設定,scrapy結合selenium需要在這裡攔截請求然後讓 selenium請求url並返回資料。。。等等),
    5. pipelines.py(管道 pipelines程式碼模組),
    6. setings.py(配置檔案)

這個是演示流程隨便建的一個,我實際建立的是這個在這裡插入圖片描述

第二步:點選capa.py 開啟檔案,寫爬蟲程式碼

  1. 進入頁面
    在這裡插入圖片描述
    發現資料都在 tebody 下的 tr 標籤裡面但是第一個 tr 和第二個 tr 標籤是表頭的一些資訊是我不要的,最後一個tr標籤裡面是頁面資訊也不是我要的所以要剔除
    所以用xpath解析到
#拿到有效資料的tr標籤列表
#xpath解析式不能有‘tebody’ 
#[2:-1]剔除掉不要的tr標籤
tr_list = response.xpath('/html/body/table//tr')[2:-1]
# 遍歷列表拿到資料
for tr in tr_list:
    day = tr.xpath('./td[1]/text()')[0].extract() #在scrapy裡面xpath解析要拿到資料後面都要加上.extract()
    center = tr.xpath('./td[2]/text()')[0].extract()#也可以寫成extract_first()
    red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
    red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
    red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
    red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
    red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
    red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
    blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()
    # 這裡就拿到了一頁的全部期號和雙色球的號碼
  1. 首頁 url = ‘http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1’
    第二頁url = ‘http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=2’ 很容易分析出規律
    所以
url = 'http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum={}'
n = 1
while n <= 132:
   new_url = url.format(n)
   n += 1
   #繫結回撥到解析的函式就可以拿到所有的資料

spider程式碼:

import scrapy
from caipiaopa.items import CaipiaopaItem  #


class CapaSpider(scrapy.Spider):
    name = 'capa'
    # allowed_domains = ['www.cc.com']
    start_urls = ['http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1'] #起始頁url
    url = 'http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1{}' 
    page = 2
    def parse(self, response):
        tr_list = response.xpath('/html/body/table//tr')[2:-1]
        for tr in tr_list:
            day = tr.xpath('./td[1]/text()')[0].extract()
            center = tr.xpath('./td[2]/text()')[0].extract()
            red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
            red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
            red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
            red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
            red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
            red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
            blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()

        while self.page <= 132:
            new_url = self.url.format(self.page)
            self.page += 1
            yield scrapy.Request(new_url, callback=self.parse) #繫結回撥(自己)

這裡只是解析出了資料,還沒有持久化儲存

第三步:將解析到的資料封裝儲存在item型別物件中。

  1. 點開 items.py 。
  2. 在class CaipiaopaItem(scrapy.Item): 裡定義我們解析出來的資料欄位,將其定義為item物件的屬性
class CaipiaopaItem(scrapy.Item):
    day = scrapy.Field()
    center = scrapy.Field()
    red1 = scrapy.Field()
    red2 = scrapy.Field()
    red3 = scrapy.Field()
    red4 = scrapy.Field()
    red5 = scrapy.Field()
    red6 = scrapy.Field()
    blue = scrapy.Field()
  1. 再開啟爬蟲檔案 把item類匯入 ,並例項化item型別物件,將資料提交。
    spider 完整程式碼:
import scrapy
from caipiaopa.items import CaipiaopaItem


class CapaSpider(scrapy.Spider):
    name = 'capa'
    # allowed_domains = ['www.cc.com']
    start_urls = ['http://kaijiang.zhcw.com/zhcw/html/ssq/list_1.html']
    url = 'http://kaijiang.zhcw.com/zhcw/html/ssq/list_{}.html'
    page = 2

    def parse(self, response):
        item = CaipiaopaItem() #例項化item型別物件
        tr_list = response.xpath('/html/body/table//tr')[2:-1]
        for tr in tr_list:
            day = tr.xpath('./td[1]/text()')[0].extract()
            center = tr.xpath('./td[2]/text()')[0].extract()
            red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
            red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
            red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
            red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
            red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
            red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
            blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()
            item['day'] = day   #資料封裝儲存在item型別物件中
            item['center'] = center
            item['red1'] = red1
            item['red2'] = red2
            item['red3'] = red3
            item['red4'] = red4
            item['red5'] = red5
            item['red6'] = red6
            item['blue'] = blue
            yield item  #將資料提交給管道

        while self.page <= 132:
            new_url = self.url.format(self.page)
            self.page += 1
            yield scrapy.Request(new_url, callback=self.parse)

第四步:在管道里接收item封裝的資料,並持久化儲存。

  1. 點開 pipelines.py 寫入持久化儲存的方法
  2. 這裡我定義了兩個類把資料一份儲存在本地csv檔案,一份存入MYSQL資料庫中
from itemadapter import ItemAdapter
import pymysql #導包


class CaipiaopaPipeline: #儲存到本地csv檔案
    fp = None  
    def open_spider(self,spider): #避免開啟檔案多次
        self.fp = open('./2000期彩票.csv', 'w', encoding='utf-8')
    def process_item(self, item, spider):
        day = item['day']
        center = item['center']
        red1 = item['red1']
        red2 = item['red2']
        red3 = item['red3']
        red4 = item['red4']
        red5 = item['red5']
        red6 = item['red6']
        blue = item['blue']
        self.fp.write(day+','+center+','+red1+','+red2+','+red3+','+red4+','+red5+','+red6+','+blue+'\n')
        return item #傳個下一個管道類接受
    def close_spider(self,spider):#關閉檔案
        self.fp.close()


class MysqlPipeline: #寫入MYSQL資料庫
    conn = None
    cou = None 
    def open_spider(self,spider):
        self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='xxx', password='xxx', db='spider', charset='utf8') #定義連線物件
        print(self.conn)

    def process_item(self, item, spider):
        day = item['day']
        center = item['center']
        red1 = item['red1']
        red2 = item['red2']
        red3 = item['red3']
        red4 = item['red4']
        red5 = item['red5']
        red6 = item['red6']
        blue = item['blue']
        #執行的mysql語句 向資料表裡面插入資料
        sql = 'insert into 彩票 values("%s","%s","%s","%s","%s","%s","%s","%s","%s")'%(day, center, red1, red2, red3, red4, red5, red6, blue)
        self.cou = self.conn.cursor() #定義遊標物件
        try: #事故處理 沒有錯誤就直接提交,插入不成功就回滾到開始的位置
            self.cou.execute(sql)
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()

        return item  #傳個下一個管道類接受
    def close_spider(self,spider): #關閉連線和遊標
        self.cou.close()
        self.conn.close()

第五步:在設定檔案中關閉robots協議,定義日誌,開啟管道類,簡單的UA偽裝
點開 setings.py

  1. 簡單的ua偽裝
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
  1. 關閉rebots協議,定義日誌型別
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR' #只輸出錯誤的日誌
  1. 開啟管道
ITEM_PIPELINES = {
   'caipiaopa.pipelines.CaipiaopaPipeline': 300, #300,301數字代表優先順序,越小優先集越高
   'caipiaopa.pipelines.MysqlPipeline': 301,
}

第六步:再次開啟終端,進入到專案目錄中輸入 > scrapy crawl spider capa 回車就ok了

這裡資料就採集完了。
本地資料部分截圖
在這裡插入圖片描述
這是資料庫裡部分截圖
在這裡插入圖片描述
因為scrapy是基於非同步爬取的所以日期都是亂的 MySQL可以按照期號順序查詢
select * from 彩票 order by 期號 ;
這樣資料就是按照順序排好的。
當然本地檔案也可以匯入到pandas進行排序。。

最後簡單的分析下資料

import pandas as pd   #資料處理和分析,清洗
#引入資料                            處理表頭       處理行索引
df = pd.read_csv('2000期彩票.csv', header=None, index_col=0)

# 把紅球號碼拿出來  行:所有行都要   列:從1到6
red_boll = df.loc[:, 2:7]#用逗號分隔 先拿行再拿列
#把藍球號碼拿出來
blue_boll = df.loc[:, 8]
# #統計每個號碼出現的頻率             扁平化處理
red_boll_count = pd.value_counts(red_boll.values.flatten())
blue_boll_count = pd.value_counts(blue_boll)
print(red_boll_count, blue_boll_count)


紅球數字出現頻率
在這裡插入圖片描述
藍球數字出現頻率
在這裡插入圖片描述
感覺都差不多,所以買彩票還是靠運氣!!

相關文章