資料提取之jsonpath

自成背後發表於2020-11-08

爬蟲中資料的分類

在爬蟲爬取的資料中有很多不同型別的資料,我們需要了解資料的不同型別來有規律的提取和解析資料。

結構化資料:json,xml等
處理方式:直接轉化為python型別

非結構化資料:HTML
處理方式:正規表示式、xpath等

在這裡插入圖片描述
其實每個方法都不難,看看使用文件都很容易理解,我一般遇到html,xml資料使用lxml裡的xpath語法解析提取,遇到json資料用jsonpath語法提取。

json的資料提取

JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,它使得人們很容易的進行閱讀和編寫。同時也方便了機器進行解析和生成。適用於進行資料互動的場景,比如網站前臺與後臺之間的資料互動。

在網站提取的json資料比較亂,如豆瓣的一條json資料:豆瓣電影影評json資料

可以放到json.cn,這個網站去解析,方便檢視結構,示例:
在這裡插入圖片描述

json模組中的方法

import json
#json.dumps 實現python型別轉化為json字串
#indent實現換行和空格
#ensure_ascii=False實現讓中文寫入的時候保持為中文
json_str = json.dumps(mydict,indent=2,ensure_ascii=False)

#json.loads 實現json字串轉化為python的資料型別
my_dict = json.loads(json_str)


#json.dump 實現把python型別寫入類檔案物件
# 具有read()或者write()方法的物件就是類檔案物件,
#比如f = open(“a.txt”,”r”) f就是類檔案物件
with open("1.txt","w") as f:
    json.dump(mydict,f,ensure_ascii=False,indent=2)

# json.load 實現類檔案物件中的json字串轉化為python型別
with open("1.txt","r") as f:
    my_dict = json.load(f)

jsonpath模組的學習

jsonpath是用來解析多層巢狀的json資料;JsonPath 是一種資訊抽取類庫,是從JSON文件中抽取指定資訊的工具,提供多種語言實現版本,包括:Javascript, Python, PHP 和 Java。

安裝方法:pip install jsonpath
官方文件:http://goessner.net/articles/JsonPath

jsonpath語法

在這裡插入圖片描述
使用示例,如下面:

{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

在這裡插入圖片描述

小案例1拉鉤json解析

簡單示例,如獲取拉鉤網[拉鉤json資料],(https://www.lagou.com/lbs/getAllCitySearchLabels.json)所有城市名字,資料在json.cn網站上解析是這樣的在這裡插入圖片描述
因此獲取城市名字的jsonpath語法可以這樣寫$..name,python程式碼示例:

import jsonpath
import json
import requests

url = 'https://www.lagou.com/lbs/getAllCitySearchLabels.json'
headers_ = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
        }

str_data = requests.get(url,headers = headers_).text
dict_data = json.loads(str_data)
# 第一個引數是字典物件,第二個引數是jsonpath表示式
ret = jsonpath.jsonpath(dict_data, '$..name')
print(ret)

小案例2 豆瓣影評案例:


import requests
import json
import jsonpath
import time


class DouBanSpider:
    # 初始化設定url,使用者代理
    def __init__(self):
        """
        1:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=0&limit=20
        2:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=20&limit=20
        3:https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=40&limit=20
        """
        # 把發生變化的引數部分 start 拿掉
        self.url_ = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&&limit=20'
        # 使用者代理UA
        self.headers_ = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
        }

    # 傳送請求,得到相應,提取內容
    def send_request(self, page):  # 只傳送一個請求,翻頁不再這裡做
        # url引數字典的設定
        page_params = {
            'start': int(page) * 20
        }
        # 傳送get請求, 得到物件的響應物件
        response_ = requests.get(self.url_, headers=self.headers_, params=page_params)
        py_data = response_.json()  # 直接把響應物件的json str 轉換成了 python型別的資料
        return py_data  # 還沒有解析過的整個json的資料

    # 解析完儲存再本地
    def save_data(self, data_):  # 接受的json資料之後 解析儲存
        title_list = jsonpath.jsonpath(data_, '$..title')  # 取到名稱 列表
        score_list = jsonpath.jsonpath(data_, '$..score')  # 取到評分 列表

        # 儲存在本地
        for i in range(len(title_list)):
            dict_ = {}
            dict_[title_list[i]] = score_list[i]  # 是一個字典
            # 儲存成json格式
            json_data = json.dumps(dict_, ensure_ascii=False) + ',\n'  # 為了每條資料換行
            with open('douban.json', 'a', encoding='utf-8') as f:
                f.write(json_data)

    # 排程方法

    def run(self):
        pages = int(input('請輸入你想要抓取的頁數:'))
        for page in range(pages):
            # 呼叫傳送請求的方法
            data_ = self.send_request(page)
            #    儲存
            self.save_data(data_)
            print(f'第{page+1}頁資料儲存完畢......')
            time.sleep(1)


if __name__ == '__main__':
    douban_ = DouBanSpider()
    douban_.run()

相關文章