Python爬蟲實戰之蘿蔔投研

SilenceHL發表於2021-04-04

宣告:以下內容均為我個人的理解,如果發現錯誤或者疑問可以聯絡我共同探討

爬蟲介紹

網站介紹

本次要爬取的網站為蘿蔔投研,是利用人工智慧、大資料、移動應用技術,建立的股票基本面分析智慧投研平臺,在進行投資交易的時候可以使用期研報與各類資料進行分析。

編寫爬蟲的原因和用途

本人閒暇時間會學習投資理財相關內容,蘿蔔投研可以獲取許多財經類的資訊與很多研報,本次想通過編寫爬蟲完成對目標資料完成持久化儲存與相關輿情完成程式提醒的目標,由於網站內容十分豐富,一次很難將其全部爬取完畢,本次想通過Scrapy獲取首頁的投研資訊,並完成翻頁的目標,後期還會持續更新,嘗試將整個網站都爬下來。(僅供個人研究使用)

Scrapy

簡介

Scrapy是一個為了爬取網站資料,提取結構性資料編寫的爬蟲框架,只需要很少的程式碼就可以完成相關資料的抓取。

Scrapy是一個使用了Twisted的非同步網路框架,可以大大提高我們的下載速度。

使用教程

Scrapy的相關使用教程可以通過官方文件來進行初步入門,瞭解各模組在框架中的作用,官方文件非常強大,建議先進行系統性的學習之後再開始使用。

學習Scrapy最重要的就是理解Scrapy的工作流程,跟著官方文件的例子去詳細分析每一步的操作,與之前編寫爬蟲的流程相關性與區別。

抓包工具

什麼是抓包工具

抓包工具是攔截檢視網路資料包內容的軟體。通過對抓獲的資料包進行分析,可以得到有用的資訊。

為什麼要用

較為複雜的網站在進行爬取資料分析的時候使用瀏覽器中的除錯工具會比較麻煩,這時候就可以用抓包工具去分析對應的請求,從而更快發現我們需要的資料所在的URL和整個請求的過程

使用與抓包工具的推薦

抓包工具的使用推薦學習朱安邦的部落格中的教程,他講了三個:Charles、Fiddler、wireshark,這些抓包工具功能各異,但基本原理相同,找一個順手的學習基本上已經足夠了。

業務邏輯分析

尋找載入資料的URL

通過對整個首頁載入的流程進行抓包與分析,發現首頁資料的URL為https://gw.datayes.com/rrp_mammon/web/feed/list,下一頁的URL為:https://gw.datayes.com/rrp_mammon/web/feed/list?timeStamp=20210401170127&feedIds=66233,66148

翻頁引數解析

通過觀察URL發現timeStamp和feedIds是兩個控制翻頁的引數,進一步多頁進行請求發現20210401170127可以理解為一個時間節點,看到20200228猜測是本次重新整理的時間,猜測後6位是當前時間的秒的時間戳,組織一下可以寫成''.join(str(datetime.now())[:10].split('-'))+str(time.clock( )).split('.')[1]

再進行多頁的資料獲取後發現feedIds引數中的前四個是第一個響應中前四個資料的id,最後一個數為響應中最後一個資料的id,並且會隨著訪問變多而增加,每次新增的都是最後一個資料的id,將下一頁的URL拼接起來,進行訪問發現請求不到下一頁的資料。通過複製原來的timeStamp發現可以訪問,問題就出現在前面timeStamp的引數,剛剛再進行feedIds欄位拼接的時候發現有三個欄位是日期形式的,分別為:"insertTime"updateTimepublishTime,進一步分析發現將其後面三個0去掉就是一個時間戳,對其轉換發現就是我們需要的結果

模擬請求測試

scrapy shell

scrapy shell可以幫助我們模擬請求地址,並進入一個互動式終端,在互動式終端中我們可以檢視請求的各類資訊,並進行除錯。但scrapy shell也有缺陷,不能解析response的格式,看起來比較亂等,這時候可以通過結合Postman來協同除錯。

Postman

簡介

Postman是一種網頁除錯與傳送網頁http請求的chrome外掛。我們可以用來很方便的模擬各種型別的請求來除錯 介面。在爬蟲中可以用於驗證我們的思路。

使用與漢化

Postman官方的使用教程非常詳細,可以跟著官方的使用教程中學習,如果想使用中文的版本可以在Postman漢化中下載。

實際使用

通過Postman傳送請求,可以得到我們想要的資料,並且可以得到格式化後的資料,看起來條理更加清晰,再配合scrapy shell除錯可以很容易就獲得我們需要的資料

編寫爬蟲

建立爬蟲專案

scrapy startproject datayes

robots協議

在settings.py中可以通過設定ROBOTSTXT_OBEY = True遵守robots.txt 的規則。

建立爬蟲

scrapy genspider mammon gw.datayes.com

修改start_urls

預設的start_urls不是我們要爬取的連結,修改為我們需求的連結

start_urls = ['https://gw.datayes.com/rrp_mammon/web/feed/list']

完成parse方法

根據之前分析的結果設計方案完成parse,這次難度主要在於如何拼接next_url,由於feedIds引數存在著累加的關係所以將其放在了parse函式外讓其可以再訪問的時候累加處理。

class MammonSpider(scrapy.Spider):
    name = 'mammon'
    allowed_domains = ['gw.datayes.com']
    start_urls = ['https://gw.datayes.com/rrp_mammon/web/feed/list']
    # 構建一個基礎next_url
    next_url = 'https://gw.datayes.com/rrp_mammon/web/feed/list?timeStamp='
    # 構建一個基礎feedIds
    feedIds = '&feedIds='

    def parse(self, response):
        # 將獲取到的資料通過json轉成字典的形式
        result = json.loads(response.text)
        # 當訪問成功時進行資料獲取
        if result['message'] == 'success':
            data_list = result['data']['list']
            for data in data_list:
                item = {}
                detail_id = data['id']  # id
                # 通過詳情頁id構造詳情頁url並訪問
                detail_url = 'https://gw.datayes.com/rrp_mammon/web/feed?id=' + str(detail_id)
                yield scrapy.Request(detail_url, callback=self.detail_parse, meta={'item': item})

                item['title'] = data['title']  # 標題
                item['publish_time'] = int(data['publishTime'] / 1000)  # 釋出時間
                item['author'] = data['roboColumn']['name']  # 作者
                item['Avatar'] = data['roboColumn']['logo']  # 頭像
                related_list = data['related']
                item['related_stocks'] = []  # 相關股票列表
                for stocks in related_list:
                    item['related_stocks'].append(stocks['targetName'])

                # 尋找出url的第0,1,2,3位置的id,加入feedIds
                if response.request.url == 'https://gw.datayes.com/rrp_mammon/web/feed/list' and data_list.index(data) in [0, 1, 2, 3]:
                    self.feedIds = self.feedIds + str(detail_id) + ','
            # 構建timeStamp引數
            timeStamp = time.strftime("%Y%m%d%H%M%S", time.localtime(item['publish_time']))
            # 拼接feedIds引數
            self.feedIds = self.feedIds + str(detail_id) + ','
            # 組合next_url
            next_url = self.next_url + timeStamp + self.feedIds
            # 請求下一頁
            yield scrapy.Request(next_url, callback=self.parse)

    def detail_parse(self, response):
        result = json.loads(response.text)
        if result['message'] == 'success':
            item = response.meta['item']
            item['content'] = result['data']['longDocContent']
            yield item

通過爬蟲觀察到兩日的cookie發生了變化,只有登入之後會保持cookie,並對cookie中的引數進行檢測,找到cloud-sso-token為必要引數,並將其新增在settings.py中。

完成資料儲存

先在settings.py中配置pipeline,和資料庫相關引數

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'datayes.pipelines.DatayesPipeline': 300,
}
# MySQL相關配置
HOST = 'HOST',  # 資料庫地址
PORT = 3306,  # 資料庫埠
DB = 'DB',  # 資料庫名
USER = 'USER',  # 資料庫使用者名稱
PASSWORD = 'PASSWORD',  # 資料庫密碼

在我們定義的DatayesPipeline類中新增open_spider和close_spider方法,通過spider.settings來匯入資料庫相關引數

import pymysql


class DatayesPipeline:
    # 爬蟲開始時執行,只執行一次
    def open_spider(self, spider):
        # 通過pymysql連結MySQL資料庫
        self.connect = pymysql.connect(
            host=spider.settings.HOST,  # 資料庫地址
            port=spider.settings.PORT,  # 資料庫埠
            db=spider.settings.DB,  # 資料庫名
            user=spider.settings.USER,  # 資料庫使用者名稱
            passwd=spider.settings.PASSWORD,  # 資料庫密碼
            charset='utf8',  # 編碼方式
            use_unicode=True)
        # 通過cursor執行增刪查改
        self.cursor = self.connect.cursor()

    # 爬蟲結束時執行,只執行一次
    def close_spider(self, spider):
        self.connect.close()

    def process_item(self, item, spider):
        self.cursor.execute(
            """insert into mammon (title, publish_time,author,avatar,related_stocks,content)value (%s, %s,%s, %s,%s, %s)""",
            (item['title'], item['publish_time'], item['author'], item['avatar'], item['related_stocks'],
             item['content']))
        # 提交sql語句
        self.connect.commit()
        return item

最後建立資料庫,開啟爬蟲進行資料爬取。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章