数据提取(json)

文章目录

数据提取概念

  • 什么是数据提取?

      简单的来说,数据提取就是从响应中获取我们想要的数据的过程
    

数据提取(json)

数据分类

  • 非结构化数据, 如html

  •   处理方法: 正则表达式/xpath
    

html数据
数据提取(json)

  • 结构化数据, 如json/xml

      - 处理方法: 使用json或xpath转换为Python对应的数据类型
    
  • JSON

  • 数据提取(json)

  • XML

  <bookstore>
    <book category="COOKING">
      <title lang="en">Everyday Italian</title> 
      <author>Giada De Laurentiis</author> 
      <year>2005</year> 
      <price>30.00</price> 
    </book>
    <book category="CHILDREN">
      <title lang="en">Harry Potter</title> 
      <author>J K. Rowling</author> 
      <year>2005</year> 
      <price>29.99</price> 
    </book>
    <book category="WEB">
      <title lang="en">Learning XML</title> 
      <author>Erik T. Ray</author> 
      <year>2003</year> 
      <price>39.95</price> 
    </book>
    </bookstore>

JSON数据提取

  1. JSON的概念
    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。

  2. JSON与前后台交互
    JSON在数据交换中起到了一个载体的作用,承载着相互传递的数据
    数据提取(json)

json模块

  1. json模块概述:
    json模块是Python自带的模块, 用于json与python数据之间的相互转换.
  2. 使用json模块处理JSON数据
    数据提取(json)
  • 什么是包含json的类文件对象?
  •   就是一个使用open打开的指向json格式文件的对象
      rf = open("xx.json", 'r') 这里rf就是
      wf = open("xx.json", "w") 这里wf也是
    
  • dump与dumps的两个参数
    • ensure_ascii: 是否使用ascii方式写入,默认True, 中文就会显示编码的后内容,如果指定False则以UTF-8编码写入,此时打开文件也必须指定UTF-8
    • indent: 用于指定代码块之间缩进几个空格
      测试代码

json模块使用

import json

  # 准备json格式的字符串
  json_str = '{"a":10, "b":20, "c":true, "d":["a","b","中文"]}'

  # 把json字符串转为为python
  dic = json.loads(json_str)
  print(dic)
  # 把python中数据类型转换为json字符串
  json_s = json.dumps(dic)
  print(json_s)

  # 操作文件
  # with open("test.json", 'w', encoding='utf8') as f:
  #     json.dump(dic, f)

  with open("test.json", 'w', encoding='utf8') as f:
      json.dump(dic, f, ensure_ascii=False, indent=2)

实例:获取豆瓣热映电影信息

需求: 获取获取热映电影信息, 保存到文件中
数据提取(json)

实现爬虫四部曲:

准备URL
发送请求,获取响应数据
解析响应数据
保存解析后的数据

# 1. 准备URL
#      - 准备一个获取豆瓣热映电影信息的json数据的URL
#      - 如果电脑web版没有找到json数据, 可以尝试使用手机版
#       https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?start=0&count=18&loc_id=108288
# 豆瓣电影json数据对用的URL
douban_movie_url = "https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?start=0&count=18&loc_id=108288"

# 2. 根据这个URL,发送请求获取热映电影json数据
# 2.1 直接发送请求,获取的数据是错误的,但是我们浏览器确实可以获取正确数据
# 2.2 我们在发送请求的时候,模拟浏览器,要模拟更像一点. 增加请求头相关信息
# 定义请求头
headers = {
    "Referer": "https://m.douban.com/movie/nowintheater?loc_id=108288",
    "User-Agent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Mobile Safari/537.36"
}

response = requests.get(douban_movie_url, headers=headers)
# 通过response获取我们要的json数据
json_str = response.content.decode()
# print(json_str)
# 3. 解析数据(json) -> 把json字符串 -> python数据类型
movie_items = json.loads(json_str)
# print(movie_items)
# 4. 保存数据
with open("douban_movie.json", 'w', encoding='utf8') as f:
    json.dump(movie_items, f, ensure_ascii=False, indent=4)

使用来封装上面的代码

也就是把代码封装到类中, 每一个功能通过方法实现

class DoubanMovieSpider(object):

    def __init__(self):
        ''' 初始化方法 '''
        # 模板URL
        self.url_pattern = "https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?start={}&count=18&loc_id=108288"
        # 请求头
        self.headers = {
            "Referer": "https://m.douban.com/movie/nowintheater?loc_id=108288",
            "User-Agent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Mobile Safari/537.36"
        }

    def get_json_from_url(self, url):
        '''
        # 2. 根据这个URL,发送请求获取热映电影json数据
        :param url: 请求的URL
        :return: json格式的字符串
        '''
        response = requests.get(url, headers=self.headers)
        return response.content.decode()

    def get_movie_list(self, json_str):
        '''
        3. 解析数据(json), 返回电影的列表信息
        :param json_str:  json字符串
        :return: 电影的列表信息
        '''
        dic = json.loads(json_str)
        # 通过字典获取电影的列表数据
        movie_list = dic['subject_collection_items']
        return movie_list

    def save_movie_list(self, movie_list):
        '''
        # 4. 保存数据, 每一个电影信息保存到一行上
        :param movie_list: 电影列表信息
        '''
        # 为了提高写数据的效率,先打开文件在遍历. 每一次打开文件都比较消耗性能的.
        with open("movies.txt", 'a', encoding='utf8') as f:
            for movie in movie_list:
                json.dump(movie, f, ensure_ascii=False)
                f.write("\n")


    def run(self):
        '''
        这是这个爬虫的入口方法
        '''
        # 定义一个变量,用于记录起始索引号
        url = self.url_pattern.format(0)
        # 2. 根据这个URL,发送请求获取热映电影json数据
        json_str = self.get_json_from_url(url)
        # 3. 解析数据(json), 获取电影列表信息
        movie_list = self.get_movie_list(json_str)
        # 4. 保存数据, 每一个电影信息保存到一行上
        self.save_movie_list(movie_list)

实现分页效果

  • 要实现分页,必须找到找到下一页的URL,由于下一页与这一页数据格式是一样的, 所以可以使用循环来实现, 并且在没有数据的时候退出
  • 豆瓣电影的实现方式有两种:
方式1: 根据URL规律找生成下一页URL,当返回的数据条数小于请求的数据条数的时候退出

数据提取(json)

变化的代码

def run(self):
        '''
        这是这个爬虫的入口
        '''
        # 定义一个变量,用于记录起始索引号
        start = 0
        while True:
            # 1. 准备URL
            url = self.url_pattern.format(start)
            # 2. 根据这个URL,发送请求获取热映电影json数据
            json_str = self.get_json_from_url(url)
            # 3. 解析数据(json), 获取电影列表信息
            movie_list = self.get_movie_list(json_str)
            # 4. 保存数据, 每一个电影信息保存到一行上
            self.save_movie_list(movie_list)
            start += 18
            #  如果这次请求返回的数据不足18条,就可以结束
            if len(movie_list) < 18:
                break
方式2:

'根据返回的数据计算出下一页的起始索引号, 如果起始索引号比总条数还大就说明没有数据了, 结束循环:
数据提取(json)
变化的代码

def get_movie_list(self, json_str):
        '''
        3. 解析数据(json), 返回电影的列表信息
        :param json_str:  json字符串
        :return: 电影的列表信息
        '''
        dic = json.loads(json_str)
        # 计算下一页起始号
        # 本次获取的电影的条数
        count = dic['count']
        # 本次获取的请求是起始号是几
        start = dic['start']
        # 计算下一页的起始号
        next_start= start + count
        # 如果下一页开始的页码数大于登录总条数, 就没有下一页了
        if next_start >= dic['total']:
            next_start = None

        # 通过字典获取电影的列表数据
        movie_list = dic['subject_collection_items']
        return movie_list, next_start

    def run(self):
    '''
    这是这个爬虫的入口方法
    方式2: 根据这一次请求的结果,计算下一页起始页号, 如果技术处理的起始页号比总数还大, 就结束
    '''
    # 定义一个变量,用于记录起始索引号
    start = 0
    while True:
        # 1. 准备URL
        url = self.url_pattern.format(start)
        # 2. 根据这个URL,发送请求获取热映电影json数据
        json_str = self.get_json_from_url(url)
        # 3. 解析数据(json), 获取电影列表信息
        movie_list, start = self.get_movie_list(json_str)
        # 4. 保存数据, 每一个电影信息保存到一行上
        self.save_movie_list(movie_list)
        # start为None就结束循环
        if start is None:
            break
上一篇:python3.7爬取唐探3,李焕英豆瓣短评,来一波词云秀


下一篇:实训day3-python爬虫原理