1. 程式人生 > >scrapy爬蟲框架簡單入門例項(二)

scrapy爬蟲框架簡單入門例項(二)

接著上一篇文章,我們已經可以用爬蟲訪問目標網站爬取頁面了,現在需要自動提交表單查詢資料,並且從頁面中篩選出每期中獎號碼儲存為json檔案匯出。首先建立一個scrapy.Item類(開啟專案資料夾下的items.py檔案):

import scrapy


class SsqSpiderItem(scrapy.Item):
    issue_num = scrapy.Field()
    red = scrapy.Field()
    blue = scrapy.Field()

我們需要爬取每期中獎號碼的期數,以及紅球陣列和藍球號;定義屬性值為scrapy.Field()。然後回到爬蟲程式碼引入這個類:

from ssq_spider.items import SsqSpiderItem

直接貼一個寫好的程式碼:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request, FormRequest
from ssq_spider.items import SsqSpiderItem


class SsqSpider(scrapy.Spider):
    name = 'ssq'
    allowed_domains = ['http://zst.aicai.com/ssq/']  # 爬取域名
    # start_urls = ['http://zst.aicai.com/ssq/']
    # 爬取網址,只適於不需要提交cookie的網站,因為沒法設定cookie等資訊
    scope_date = [['2012001', '2014200'], [
        '2015001', '2017200'], ['2018001', '2018130']]

    # 設定瀏覽器使用者代理
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0'}

    def start_requests(self):
        # 第一次請求頁面,設定開啟cookie使其得到cookie,設定回撥函式
        return [Request('http://zst.aicai.com/ssq/', meta={'cookiejar': 1}, callback=self.parse)]

    def parse(self, response):
        print('請求頭資訊')
        print(response.request.headers)
        print('響應頭資訊')
        print(response.headers)
        print(response.status)
        print('---Cookie---')
        # 請求Cookie
        request_Cookie = response.request.headers.getlist('Cookie')
        print(request_Cookie)
        # 響應Cookie
        response_Cookie = response.headers.getlist('Set-Cookie')
        print(response_Cookie)
        print('---end---')
        # 設定提交表單資訊,對應抓包得到欄位
        for i in SsqSpider.scope_date:
            form_data = {
                'startIssue': i[0],
                'endIssue': i[1],
                'sIssue': '',
                'eIssue': '',
                'maxsize': '30',
                'openDate': '',
                'statisticsTag': '1',
                'sortTag': 'up'
            }
            # 第二次用表單post請求,攜帶Cookie、瀏覽器代理等資訊給Cookie授權
            yield FormRequest.from_response(response,
                                            url='http://zst.aicai.com/ssq/',  # 真實post地址
                                            meta={'cookiejar': response.meta[
                                                'cookiejar']},
                                            headers=self.header,
                                            formdata=form_data,
                                            callback=self.next,
                                            dont_filter=True
                                            )

    def next(self, response):
        items = SsqSpiderItem()
        print(response.css('title').extract())
        html_tr = response.css('#tdata tr:not(.tdbck)')
        for i in html_tr:
            items['issue_num'] = i.css('td:nth-child(1)::text').extract()[0]
            items['red'] = i.css('.chartBall01::text').extract()
            items['blue'] = i.css('.chartBall02::text').extract()[0]
            yield items

從response物件中用scrapy自帶的css選擇器解析提取出資料,執行命令就可以匯出json檔案:

scrapy crawl '爬蟲名稱' -o items.json

或者通過配置pipelines匯出json檔案,開啟pipelines.py:

import codecs
import os
import json


class JsonPipeline(object):
    def process_item(self, item, spider):
        base_dir = os.getcwd()
        filename = base_dir + '/ssq_item.json'
        # 開啟json檔案,以dumps的方式將一個Python資料型別列表進行json格式的編碼
        # 注意需要有一個引數ensure_ascii=False ,不然資料會直接為utf編碼的方式存入
        with codecs.open(filename, 'a') as f:
            line = json.dumps(dict(item), ensure_ascii=False) + ',\n'
            f.write(line)
        return item

接著編寫settings.py ,我們需要在Settings.py將我們寫好的pipeline新增進去,這裡只需要增加一個dict格式ITEM_PIPELINES,數字value可以自定義,數字越小的優先處理。

ITEM_PIPELINES = {
    'ssq_spider.pipelines.JsonPipeline': 300,
}

執行爬蟲就能匯出json:

scrapy crawl '爬蟲名稱'

需要注意的是,這樣匯出的json檔案格式不太嚴謹(缺少[ ]字元,程式直接讀取json檔案會報錯);由於scrapy框架為了執行更有效率,採用的是多執行緒並行爬取,所以爬取的資料沒有順序:

強迫症表示不能忍,新建一個python檔案用來排序:

import json


def sorting_json():
    with open('./spiders/ssq_item.json', 'r', encoding='utf-8') as s_i:
        json_data = json.load(s_i, strict=False)
        # 利用issue_num欄位排序
        json_data.sort(key=lambda x: x['issue_num'], reverse=True)
        return json_data

with open('ssq.js', 'a') as s:
    n = sorting_json()
    for i, value in enumerate(n):
        if i == 0:
            s.write('var ssq_data = [')
        line = json.dumps(dict(value), ensure_ascii=False) + ',\n'
        if i == len(n) - 1:
            line = json.dumps(dict(value), ensure_ascii=False) + ']'
        s.write(line)

有了資料,就可以為所欲為了(邪魅一笑~):

隨便用js寫了個程式碼,想看看從2012年到現在有沒有2期6個紅球完全相同的情況,可惜沒有;5個紅球相同倒是有,而且13年有相鄰的兩期5個紅球和藍球號都一樣。(被安排的明明白白……)

感慨一下,寫爬蟲其實不難,難的是反爬處理,這裡推薦一個連結:https://weibo.com/ttarticle/p/show?id=2309404125351516226870