爬蟲爬 JSON HTML 數據

最近這兩週在忙着給公司爬一點數據,更文的速度有一點下降,預計今天就爬完了,總結總結經驗。

其實之前我司是有專門做爬蟲的,不用前端這邊出人幹活。後來那人離職了,有可能就沒有爬蟲這方面的需求了。突然又有了一些,前端這邊出人做一下。老大說用 py 做,前期先調研一下。

原理

爬蟲其實原理上很簡單,我們==客戶端他們==服務端
客戶端發送請求 req,服務端返回響應 rsp。拿到響應之後解析數據,入庫,就完事了。

請求數據 req

一般來說請求分爲兩種,拉數據 get 比較多。
偶爾部分接口需要登錄,那就是多帶 cookie 或者 headers
其實還有一部分工作就是分析入參

  1. get
    參數拼接在 url
  2. post
    參數放在 body

響應數據 rsp

返回數據大體上是兩種

  1. JSON
    一般來說,通過 抓包 或者說 network 工具。我們找到了服務端的接口,那麼我直接訪問這個接口即可。
    本文第一個重點來了:切換到移動端再查一遍,往往有不一樣的收穫,一般來說 PCM 端的進度不了,有可能都不是一個項目組,所以實現方式就會有差別。
  2. html
    比較坑的一種方式,因爲沒有找到 JSON 接口。無奈只能走解析 HTML 的路子。

調研

  1. Node
    之前給後臺搭架子的時候使用過,主要功能點如下:

    1. 自動登錄,(拿headers、cookie
    2. 存儲本地,每次請求帶上 token
    3. 啓動代理服務
  2. py 老大說要用這個東西。諮詢了一下其他朋友,說可以使用下面的工具。

    1. requests + beautifulSoup
      使用起來其實就是 requests 發請求, beautifulSoup 解析 HTML。比較原始。
    2. scrapy
      一個爬蟲的框架。我在這裏學的 www.scrapyd.cn。實現上比較完整,可以設置請求間隔,隨機 ua 等功能。
  3. 前端實現
    我一個鐵頭娃,怎麼能輕言放棄?身爲一個前端er,還是這些 api 讓我更加親切

    1. XHR
      發請求利器,打開對方頁面,cookie 啥的都自帶。無敵就是這麼寂寞
      其實還可以找到對方請求發起的位置,打個斷點,把對方內部的代碼綁定到全局,這樣一些內部邏輯什麼的也都沒問題。
      而且還 JSON HTML 通吃。
    2. iframe
      針對 HTML 類型的處理。同域的情況下,也無敵好嗎?

      1. HTML 獲取 DOM 節點?
      2. 甚至可以取 window 上的對象。vue SSR 你感覺到了威脅嗎?
  4. 網上其他服務商提供的接口(真香啊)。有免費的有收費的,一般免費的限量。

    1. 比如抖音熱度?
    2. 比如各類音樂的歌單和作品?
    3. IP 查詢
    4. 天氣查詢

好了上面說了那麼多,建議老大限制,我選擇了 scrapy

scrapy

scrapy 是一個網頁爬蟲框架,神馬叫做爬蟲,如果沒聽說過,那就:內事不知問度娘,外事不決問谷歌,百度或谷歌一下吧!……(這裏的省略號代表 scrapy 很牛逼,基本神馬都能爬,包括你喜歡的蒼老師……這裏就不翻譯了)

看到這個騷的飛起的介紹了嗎?沒錯,我就是在上面學的。scrapy 中文站。接下來我就介紹一下我認爲對於新手比較關注的東西

scrapy HTML

scrapy 處理器中的 response 標識你拿到的 rsp 上面自帶了一些方法,一般來說需要關注的只有兩個

css 選擇器

quote.css('span.text::text').extract_first() 中的 'span.text::text'眼熟嗎?
沒錯,就是我們常用的選擇器。通過這個 api,我們可以把我們想要的數據,限時在一個很小的範圍,然後拿字符串即可。
啥?你說你不會 css 選擇器?前端培訓-初級階段(5 - 8)-CSS選擇器(基本、層級、屬性、僞類、僞狀態)

  1. extract() 函數提取列表
  2. extract_first() 代表提取第一個元素。基本等價於 extract()[0]
  3. ::text 選擇其中的文字
  4. ::attr(href) 提取屬性

xpath

quote.xpath('span/small/text()').extract_first()
文檔,這個我不會,我也沒看

scrapy JSON

import json 使用這個類庫解析如:json.loads(response.body.decode('utf-8'))

scrapy 請求方式

get

import urllib 可以用來給中文字符 encode

yield scrapy.FormRequest(
    url, 
    method = 'GET', 
    headers = self.headers, 
    formdata={}, 
    callback = self.parse_list, 
    dont_filter = True, 
    meta = {
        'offset': 0,
    })

post

數據放入 formdata 傳遞即可。

yield scrapy.FormRequest(
    url, 
    method = 'GET', 
    headers = self.headers, 
    formdata={}, 
    callback = self.parse_list, 
    dont_filter = True, 
    meta = {
        'offset': 0,
    })

外部傳參方式

scrapy crawl argsSpider -a tag=愛情
內部是使用如下命令可以接收到。

    def start_requests(self):
        url = 'http://lab.scrapyd.cn/'
        tag = getattr(self, 'tag', None)  # 獲取tag值,也就是爬取時傳過來的參數

scrapy mysql

大數據那邊說爬回來的數據要入庫。

  1. scrapyMysql/scrapyMysql/items.py 編寫對應入庫字段。

    import scrapy
    
    class ScrapymysqlItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        tag = scrapy.Field()  # 標籤字段
        cont = scrapy.Field()  # 名言內容
        pass
  2. scrapyMysql/scrapyMysql/spiders/inputMysql.py 寫爬蟲處理操作時,入庫

    item = ScrapymysqlItem()  # 實例化item類
        for v in mingyan:  # 循環獲取每一條名言裏面的:名言內容、作者、標籤
            item['cont'] = v.css('.text::text').extract_first()  # 提取名言
            tags = v.css('.tags .tag::text').extract()  # 提取標籤
            item['tag'] = ','.join(tags)  # 數組轉換爲字符串
            yield item  # 把取到的數據提交給pipline處理
  3. 編寫MySQL存儲插件:MySQLPipeline.py

    import pymysql.cursors
    class MySQLPipeline(object):
        def __init__(self):
            # 連接數據庫
            self.connect = pymysql.connect(
                host='127.0.0.1',  # 數據庫地址
                port=3306,  # 數據庫端口
                db='scrapyMysql',  # 數據庫名
                user='root',  # 數據庫用戶名
                passwd='root',  # 數據庫密碼
                charset='utf8',  # 編碼方式
                use_unicode=True)
            # 通過cursor執行增刪查改
            self.cursor = self.connect.cursor()
    
        def process_item(self, item, spider):
            self.cursor.execute(
                """insert into mingyan(tag, cont)
                value (%s, %s)""",  # 純屬python操作mysql知識,不熟悉請惡補
                (item['tag'],  # item裏面定義的字段和表字段對應
                 item['cont'],))
            # 提交sql語句
            self.connect.commit()
            return item  # 必須實現返回
  4. settings啓動MySQLPipline組件

    ITEM_PIPELINES = {
       'scrapyMysql.MySQLPipline.MySQLPipeline': 300,
    }

總結一下

到現在,我們已經完成了所有基礎知識的積累。遇到不會我們去裏看?
總結一下需要注意點的

  1. 切換 PC 和 M 端,尋找可行的方案
  2. 注意節制(部分容易限量)
  3. python 編碼問題(真的好煩)
  4. 網上提供的那個 mysql 庫和我的不合,我換了一個MySQLdb
  5. 第三方的接口是真香

微信公衆號

clipboard.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章