数据提取1

数据提取概述

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

在这里插入图片描述

1.响应内容的分类

在发送请求获取响应之后,可能存在多种不同类型的响应内容;而且很多时候,我们只需要响应内容中的一部分数据

  • 结构化的响应内容

    • json字符串

      • 可以使用re、json等模块来提取特定数据
      • json字符串的例子如下图

      在这里插入图片描述

    • xml字符串

      • 可以使用re、lxml等模块来提取特定数据

      • 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>
        
  • 非结构化的响应内容

    • html字符串

      • 可以使用re、lxml等模块来提取特定数据
      • html字符串的例子如下图

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FlGbTxcO-1658849811585)(../img/非结构化响应内容html.png)]

2. 认识xml以及和html的区别

要搞清楚html和xml的区别,首先需要我们来认识xml

认识xml

xml是一种可扩展标记语言,样子和html很像,功能更专注于对传输和存储数据

<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>

上面的xml内容可以表示为下面的树结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oBR59snJ-1658849811586)(../img/xml树结构.gif)]

xml和html的区别

二者区别如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4YsK7tj-1658849811587)(../img/xml和html的区别.png)]

  • html:
    • 超文本标记语言
    • 为了更好的显示数据,侧重点是为了显示
  • xml:
    • 可扩展标记语言
    • 为了传输和存储数据,侧重点是在于数据内容本身

常用数据解析方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FplUx2O6-1658849811588)(../img/数据解析.png)]

数据提取之json

目标:理解json的概念

​ 了解爬虫中,json出现的位置

​ 掌握json相关的方法


1. 什么是json,在哪里能找到json

json是一种轻量级的数据交换格式,它使地人们很容易的进行阅读和编写,同事也方便了机器进行解析和生成,适用于进行数据交互的场景,比如web的前台和后台之间的数据交互

至于在哪里能找到能返回json数据的url,以豆瓣电影为例,下面这条url就是返回json数据的url

https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0

在url地址对应的响应中搜索关键字即可

但是注意:url地址对应的响应中,中文往往是被编码之后的内容,所以更推荐大家去搜索英文和数字;另外一个方法就是在perview中搜索,其中的类容都是转码之后的

还有一个方法,就是将浏览器切换到手机版寻找json

2. json数据格式化

在preview中观察

其中:

​ 方形方框表示json中的健

​ 椭圆框表示健所对应的值,是一个列表,在列表展开之后,下面的数字表示列表中所对应的值

在线解析工具进行解析

​ json.cn(在线json数据解析,让数据直观易读)

pycharm进行reformat code

​ 在pycharm中新建一个json文件,把数据存入后,点击code下面的reformat code,但是中文往往显示的是unicode格式

json数据的其他来源:

​ 抓包app,app的抓包方式会在后面学习,但是很多时候app中的数据是被加密的,但仍然值得尝试

3. json模块中方法的学习

json.dumps

dump的功能就是把Python对象encode为json对象,一个编码过程。注意json模块提供了json.dumps和json.dump方法,区别是dump直接到文件,而dumps到一个字符串,这里的s可以理解为string。

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print('DATA:', repr(data))

data_string = json.dumps(data)
print('JSON:', data_string)
#结果如下
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
JSON: [{"a": "A", "c": 3.0, "b": [2, 4]}]
print type(data)
print type(data_string)
<type 'list'>
<type 'str'>

json.dump

不仅可以把Python对象编码为string,还可以写入文件。因为我们不能把Python对象直接写入文件,这样会报错TypeError: expected a string or other character buffer object,我们需要将其序列化之后才可以

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
with open('output.json','w') as fp:
    json.dump(data,fp)
# 结果
[{“a”: “A”, “c”: 3.0, “b”: [2, 4]}]

json.loads

从Python内置对象dump为json对象我们知道如何操作了,那如何从json对象decode解码为Python可以识别的对象呢?是的用json.loads方法,当然这个是基于string的,如果是文件,我们可以用json.load方法。

decoded_json = json.loads(data_string)
# 和之前一样,还是list
print type(decoded_json)
<type 'list'>
# 像访问 data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]一样
print decoded_json[0]['a']
#结果如下
A

json.load

可以直接load文件

with open('output.json') as fp:
    print type(fp)
    loaded_json = json.load(fp)

<type 'file'>
# 和之前一样,还是list
print type(decoded_json)
<type 'list'>
# 像访问 data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]一样
print decoded_json[0]['a']

#结果如下
A

4. json.dumps常用参数

一些参数,可以让我们更好地控制输出。常见的比如sort_keys,indent,separators,skipkeys等。

sort_keys名字就很清楚了,输出时字典的是按键值排序的,而不是随机的。

import json
data = [ { 'a':'A',  'c':3.0 ,'b':(2, 4)} ]
print('DATA:', repr(data))

unsorted = json.dumps(data)
print('JSON:', json.dumps(data))
print('SORT:', json.dumps(data, sort_keys=True))
#结果如下
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
JSON: [{"a": "A", "c": 3.0, "b": [2, 4]}]
SORT: [{"a": "A", "b": [2, 4], "c": 3.0}]1234567891011

indent就是更个缩进,让我们更好地看清结构。

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print('DATA:', repr(data))

print('NORMAL:', json.dumps(data, sort_keys=True))
print('INDENT:', json.dumps(data, sort_keys=True, indent=2))

#结果如下
DATA: [{'a': 'A', 'b': (2, 4), 'c': 3.0}]
NORMAL: [{"a": "A", "b": [2, 4], "c": 3.0}]
INDENT: [
  {
    "a": "A",
    "b": [
      2,
      4
    ],
    "c": 3.0
  }
1234567891011121314151617181920

separators是提供分隔符,可以出去白空格,输出更紧凑,数据更小。默认的分隔符是(‘, ‘, ‘: ‘),有白空格的。不同的dumps参数,对应文件大小一目了然。

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print('DATA:', repr(data))
print('repr(data)             :', len(repr(data)))
print('dumps(data)            :', len(json.dumps(data)))
print('dumps(data, indent=2)  :', len(json.dumps(data, indent=2)))
print('dumps(data, separators):', len(json.dumps(data, separators=(',',':'))))

#结果如下
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
repr(data)             : 35
dumps(data)            : 35
dumps(data, indent=2)  : 76
dumps(data, separators): 291234567891011121314

json需要字典的的键是字符串,否则会抛出ValueError。

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0, ('d',):'D tuple' } ]

print('First attempt')
try:
    print(json.dumps(data))
except (TypeError, ValueError) as err:
    print('ERROR:', err)

print()
print('Second attempt')
print(json.dumps(data, skipkeys=True))

#结果如下
First attempt
ERROR: keys must be a string

Second attempt
[{"a": "A", "c": 3.0, "b": [2, 4]}]

5. 案例

爬取豆瓣电视剧的英剧和美剧的数据,并分类,地址:https://m.douban.com/tv/

class Douban(object):
    def __init__(self, tv_name):
        self.start_url = 'https://movie.douban.com/j/search_subjects?type=tv&tag={}&sort=recommend&page_limit=20&page_start={}'
        self.referer = 'https://m.douban.com/movie/subject/{}/'
        self.tv_msg = 'https://m.douban.com/rexxar/api/v2/tv/{}?ck=&for_mobile=1'
        self.tv_name = tv_name

    def run(self):
        """
        拼接url,获取翻页信息
        :return:
        """
        for i in range(5):
            # 拼接url,获取翻页信息
            url = self.start_url.format(self.tv_name, i)
            # 获取url响应的json数据,并转换成字典
            tv_list_json = json.loads(session.get(url).content.decode())
            self.parse_json_data(tv_list_json)

    def parse_json_data(self, json_data):
        """
        json数据解析
        :param json_data: json_data
        :return:
        """
        # 遍历字典,获取需要的数据
        for tv in json_data['subjects']:
            # 电视剧标题
            tv_title = tv['title']
            # 电视剧的url
            tv_url = tv['url']
            # 电视剧的图片地址
            tv_img = tv['cover']
            # 电视剧的id
            tv_id = tv['id']
            self.parse_tv(tv_id, tv_title, tv_url, tv_img)

    def parse_tv(self, tv_id, tv_title, tv_url, tv_img):
        """

        :param tv_id:
        :return:
        """
        # 拼接电视剧详细信息的url
        url = self.tv_msg.format(tv_id)
        # 反反爬,拼接referer
        headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Appl\
                            eWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
                   'referer': self.referer.format(tv_id)}
        # 获取json数据,转化为字典
        tv_json_data = json.loads(session.get(url, headers=headers).content.decode('utf-8'))
        # 获取电视剧简介
        intro = tv_json_data['intro']
        self.actor_msg(tv_json_data, tv_title, tv_url, tv_img, intro)

    def actor_msg(self, tv_json_data, tv_title, tv_url, tv_img, intro):
        name = []
        # 演员在字典中,循环取出演员名
        for actor in tv_json_data['actors']:
            name.append(actor)
        self.save(name, tv_title, tv_url, tv_img, intro)

    def save(self, name, tv_title, tv_url, tv_img, intro):
        with open('tv.txt', 'a+', encoding='utf-8')as f:
            # 构造上下文
            content = {
                '类别': self.tv_name,
                '标题': tv_title,
                '播放链接': tv_url,
                '封面链接': tv_img,
                '内容简介': intro,
                '演员': name
            }
            f.write(str(content) + '\r\n')
        print('{}{}保存完成'.format(self.tv_name, tv_title))


if __name__ == '__main__':
    print("1: '美剧', 2: '英剧'")
    while True:
        num = input('请输入对应的编号, 按回车结束')
        if num == '1' or num == '2':
            data = {1: '美剧', 2: '英剧'}
            douban = Douban(data[int(num)])
            douban.run()
            continue
        if num == '0':
            break
        else:
            print('输入有误')

数据提取之jsonpath模块(我还没用过)

pip install jsonpath

使用场景:多层嵌套的复杂的字典,直接提取数据

方法:

ret = jsonpath(a, ‘jsonpath语法规则字符串’) #a是需要提取数据的目标字典

常用节点:

$ 根节点(最外层的大括号)

. 字节点()

… 内部任意位置,子孙节点

示例1:

示例2:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马航行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值