python数据提取基础

数据提取

1.数据提取概述

1.1 响应内容的分类

  • 结构化的响应内容

    • json字符串
      • 可以使用re、json等模块来提取字符串特定数据
    • xml字符串
      • 可以使用re、lxml等模块来提取特定数据
  • 非结构化的响应内容

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

1.2 认识xml和html的区别

数据格式描述设计目标
XMLExtensible Markup Language(可拓展标记语言)被设计为传输和存储数据,其焦点是数据的内容
HTMLHyperText Markup Language(超文本标记语言)显示数据以及如何更好的显示数据

1.3 常用的数据解析方法

img

2.jsonpath模块

2.1 使用场景

jsonpath可以按照key对python字典进行批量的数据提取

2.2 使用方法

  • 安装
pip install jsonpath
  • jsonpath模块提取数据的方法
from jsonpath import jsonpath
ret = jsonpath.(a, 'jsonpath语法规则字符串')

2.3 Jsonpath语法规则

jsonpath描述
$根节点
@现行节点
.or []取子节点
n/a取父节点
不管位置,选择所有符合条件的条件
*匹配所有元素节点
n/a根据属性访问,json不支持,因为json是Key-value递归结构,不需要属性访问
[]迭代器标识
[,]支持迭代器中做多选
?()支持过滤操作
()支持表达式计算
n/a分组,Jsonpath不支持

2.4 jsonpath使用

from jsonpath import jsonpath

data = {'key1': {'key2': {'key3': {'key4': {'key5':{'key6': 'python'}}}}}}

# jsonpath的结果为列表,获取数据需要索引
print(jsonpath(data, '$.key1.key2.key3.key4.key5.key6'))
print(jsonpath(data, '$..key6')[0])

2.5 jsonpath的练习

import jsonpath
import json

book_dict ="""{
  "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,
      "author": "yin"
    }
  }
} """

data = json.loads(book_dict)
print(jsonpath.jsonpath(data, '$..color'))
print(jsonpath.jsonpath(data, '$..price'))

price_list = jsonpath.jsonpath(data, '$..price')

sum = 0
for i in price_list:
    sum += i
print(sum)

# 打印store中的书的作者
print(jsonpath.jsonpath(data, '$.store.book[*].author'))
# 打印所有的作者
print(jsonpath.jsonpath(data, '$..author'))
# 打印所有的价格
print(jsonpath.jsonpath(data, '$..price'))
# 打印store中的书的价格
print(jsonpath.jsonpath(data, '$.store.book[*].price'))

# 打印第三本书
print(jsonpath.jsonpath(data, '$..book[2]'))
# 打印最后一本书
print(jsonpath.jsonpath(data, '$..book[-1:]'))
# 打印前两本书
print(jsonpath.jsonpath(data, '$..book[0,1]'))

# 获取所有价格大于10的书
print(jsonpath.jsonpath(data, '$..book[?(@.price>10)]'))
# 获取有isbn的所有数
print(jsonpath.jsonpath(data, '$..book[?(@.isbn)]'))

# 获取所有数据
print()
print(jsonpath.jsonpath(data, '$..*'))

2.6 jsonpath – 拉勾网

import requests
import jsonpath
import json

url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/11'
}
response = requests.get(url, headers=headers)

dict_data = json.loads(response.content)

print(jsonpath.jsonpath(dict_data, '$..A..name'))

3.lxml模块

3.1 了解lxml模块和xpath语法

  • lxml模块可以利用xpath规则语法,来快速的定位HTML\XML文件中特定元素以及获取节点信息(文本内容、属性值)
  • xpath是一门在HTML文档中查找信息的语言,可以在HTML文档中对元素进行遍历
    • W3School官方文档:https://www.w3school.com.cn/xpath/index.asp
  • 提取xml、html中数据需要lxml模块和xpath语法混合使用

4. xpath语法–选取节点以及提取属性或文本内容的语法

  1. Xpath使用路径表达式来选取XML文档中的节点或者节点集
  2. 这些路径表达式和我们在常规的电脑文件中看到的表达式非常相似
  3. 使用chrome插件选择标签的时候,选中时,选中的标签会添加属性class=’xh-highlight‘

4.1 xpath定位节点以及提取属性或者文本内容的语法

表达式描述
nodename选中该元素
/从根节点选取、或者是元素和元素之间的过渡
//从匹配选择的当前节点选择文档中的节点,不考虑它们的位置
.选取当前节点
选取当前节点的父节点
@选取属性
text()选取文本

5. xpath语法 – 选取特定节点的语法

5.1 选取特定节点的语法

路径表达式结果
//title[@lang=‘eng’]选取lang属性为eng的所有title元素
/bookstore/book[1]选取属于bookstore子元素的第一个book元素
/bookstore/book[last()]选取属于bookstore子元素的最后一个book元素
/bookstore/book[last()-1]选取属于bookstore子元素的倒数第二个book元素
/bookstore/book[last()>1]选取bookstore下面的book元素,从第二个开始选取
//book/title[text()=‘Harry Potter’]选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素
/bookstore/book[price>35.0]/title选取bootstore元组中的book元素的所有title元素,且其中的price的值必须大于35.0

5.2 xpath的下标

  • 在xpath中,第一个元素的位置是1
  • 最后一个元素的位置是last()
  • 倒数第二个是last()-1

6. xpath语法 – 选取未知节点的语法

6.1 选取未知节点的语法

通配符
.匹配任何元素节点
@匹配任何属性节点
node()匹配任何类型节点

7. lxml模块的安装与使用

7.1 lxml安装

pip install lxml

7.2 爬虫对html提取内容

  • 提取标签中的文本内容
  • 提取标签中的属性的值
    • 比如a标签中的href属性的值,获取url进而继续发起请求

7.3 lxml模块的使用

  1. 导入lxml的etree库
 from lxml import etree
  1. 利用etree.HTML,将html字符串转换为Element对象,Element对象具有xpath的方法,返回结果的列表
html = etree.HTML(text)
ret_list = html.xpath('xpath语法规则字符串')
  1. xpath方法返回列表的三种情况
    • 返回空列表:根据xpath语法规则字符串,没有定位到任何元素
    • 返回由字符串构成的列表:xpath字符串规则匹配到的一定是文本内容或者某属性的值
    • 返回由Element对象构成的列表:xpath规则字符串匹配的是标签,列表中的Element对象可以继续进行xpath
# 提取html中的数据
from lxml import etree


text = '''
<html>
        <div class="clearfix">
        <div class="nav_com">
          <ul>
              <li class="active"><a href="/">推荐</a></li>
              <li class=""><a href="/nav/python">Python</a></li>
              <li class=""><a href="/nav/java">Java</a></li>
              <li class=""><a href="/nav/web">前端</a></li>
              <li class=""><a href="/nav/arch">架构</a></li>
              <li class=""><a href="/nav/db">数据库</a></li>
              <li class=""><a href="/nav/5g">5G</a></li>
              <li class=""><a href="/nav/game">游戏开发</a></li>
              <li class=""><a href="/nav/mobile">移动开发</a></li>
              <li class=""><a href="/nav/ops">运维</a></li>
          </ul>
        </div>
        </div>
</html>>
</html>>
'''

# 创建element对象
html = etree.HTML(text)
# print(html)
# print(dir(html))
#
# print(html.xpath('//a[@href="/"]/text()'))  # 数据列表
# print(html.xpath('//a[@href="/"]/text()')[0])
#
# print(html.xpath('//a[@href="/nav/python"]/text()'))
# print(html.xpath('//a[@href="/nav/python"]/text()')[0])

text_list = html.xpath('//a/text()')
link_list = html.xpath('//a/@href')
# print(text_list)
# print(link_list)
#b
# for text in text_list:
#     myindex = text_list.index(text)
#     link = link_list[myindex]
#     print(text, link)

# for text, link in zip(text_list, link_list):
#       print(text, link)

el_list = html.xpath('//a')
for el in el_list:
    # print(el.xpath('//text()'))     这种方法是错误的每次回提取所有文本不是遍历
    # print(el.xpath('./text()')[0], el.xpath('./@href')[0])
    # print(el.xpath('.//text()')[0], el.xpath('.//@href')[0])
    print(el.xpath('text()')[0], el.xpath('./@href')[0])


html1 = etree.HTML(text)

handeled_html_str = etree.tostring(html).decode()
print(handeled_html_str)

8. 百度贴吧

# -*- coding: utf-8 -*-
"""
-------------------------------------------------
# @Project  :百度贴吧
# @File     :百度贴吧
# @Date     :2021/7/1 15:51
# @Author   :yin
# @Software :PyCharm
-------------------------------------------------
"""
import requests
from lxml import etree


class San(object):
    def __init__(self, name):
        self.url = 'https://tieba.baidu.com/f?kw={}&ie=utf-8&pn=0'.format(name)
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/11',
        }

    def get_data(self, url):
        response = requests.get(url, headers=self.headers)
        return response.content

    def parse_data(self, data):
        # 创建element对象
        data = data.decode().replace('<!--', '').replace('-->', '')
        html = etree.HTML(data)
        el_list = html.xpath('//*[@id="thread_list"]/li/div/div[2]/div[1]/div[1]/a')
        # print(len(el_list))

        data_list = []
        for el in el_list:
            temp = {}
            temp['title'] = el.xpath('./text()')[0]
            temp['link'] = 'https://tieba.baidu.com/' + el.xpath('./@href')[0]
            data_list.append(temp)

        # 获取下一页url
        try:
            next_url = 'https:' + html.xpath('//a[contains(text(), "下一页>")]/@href')[0]
        except:
            next_url = None
        return data_list, next_url

    def save_data(self, data_list):
        for data in data_list:
            print(data)

    def run(self):
        # url
        # headers
        next_url = self.url
        while True:
            # 发送请求,获取响应
            data = self.get_data(next_url)
            data_list, next_url = self.parse_data(data)
            self.save_data(data_list)
            print(next_url)
            # 从响应中提取数据(数据和翻页的url)
            # 判断翻页终结
            if next_url == None:
                break


if __name__ == '__main__':
    tieba = San('三国志战略版')
    tieba.run()

9. lxml模块中的etree.tostring函数的使用

# -*- coding: utf-8 -*-
"""
-------------------------------------------------
# @Project  :requests代码
# @File     :tostring
# @Date     :2021/7/1 17:43
# @Author   :yin
# @Software :PyCharm
-------------------------------------------------
"""
from lxml import etree


text = '''
<html>
        <div class="clearfix">
        <div class="nav_com">
          <ul>
              <li class="active"><a href="/">推荐</a></li>
              <li class=""><a href="/nav/python">Python</a></li>
              <li class=""><a href="/nav/java">Java</a></li>
              <li class=""><a href="/nav/web">前端</a></li>
              <li class=""><a href="/nav/arch">架构</a></li>
              <li class=""><a href="/nav/db">数据库</a></li>
              <li class=""><a href="/nav/5g">5G</a></li>
              <li class=""><a href="/nav/game">游戏开发</a></li>
              <li class=""><a href="/nav/mobile">移动开发</a></li>
              <li class=""><a href="/nav/ops">运维</a></li>
          </ul>
        </div>
        </div>
</html>>
</html>>
'''

# 创建element对象
html = etree.HTML(text)

# 将html源码转换成str类型数据
# etree.HTML()能够自动补全缺失的标签
print(etree.tostring(html))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值