04-数据解析
解析json数据
jsonpath
pip install jsonpath 下载包
jsonpath 是一种用于从 JSON 文档中提取数据的查询语言,类似于 XPath 对 XML 的作用。它提供了一种简洁的方式来定位和提取 JSON 数据中的特定部分
不能直接处理字符串格式, 能直接处理字典,列表数据
JsonPath语法使用
Json结构清晰,可读性高,复杂度低,非常容易匹配,下表中对应了XPath的用法。
| JSONPath | 描述 |
|---|---|
$ |
根节点 |
@ |
现行节点 |
.or[] |
取子节点 |
.. |
就是不管位置,选择所有符合条件的条件 |
* |
匹配所有元素节点 |
[] |
迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等) |
[,] |
支持迭代器中做多选。 |
?() |
支持过滤操作. |
openpyxl存储数据
使用 openpyxl 库创建和操作 Excel 文件
pip install openpyxl
from openpyxl import Workbookwb = Workbook() # 1. 创建一个新的工作簿 Workbook首字母大写ws = wb.active # 2. 获取当前活动的工作表(默认第一个)ws.title = "数据" #3. 设置工作表名称# 4:使用append添加一行数据 每次使用append都是一行数据ws.append(["学号", "姓名", "成绩", "是否及格"]) # 表头ws.append([1001, "张三", 85, "是"]) ws.append([1002, "李四", 92, "是"])ws.append([1003, "王五", 58, "否"])wb.save("example.xlsx") # 5. 设置文件名称与位置,以及将数据保存至这个文件中综合案例
异步读取数据, 使用jsonpath, 使用openpyxl库来操作腾讯网要闻数据并且进行翻译了
# 完整版import requestsimport json, timefrom jsonpath import jsonpathfrom openpyxl import Workbookwb = Workbook() # 创建一个xlsx表格文件ws = wb.active # 获取创建的表格文件ws.title = "新闻数据" # 设置工作表格名称ws.append(["序号", "标题", "时间", "地址", "详情"]) # 表头def spider(url, headers, data): res = requests.post(url, headers=headers, json=data) return res.json() passdef save_data(result): title = jsonpath(result, "$.data..title") # 标题 id = jsonpath(result, "$.data..id") # 序号 publish_time = jsonpath(result, "$.data..publish_time") # 时间 long_summary = jsonpath(result, "$.data..long_summary") # 详情 user_address = jsonpath(result, "$.data..user_address") # 地址 for title1, id1, publish_time1, long_summary1, user_address1 in zip(title, id, publish_time, long_summary, user_address): ws.append([id1, title1, publish_time1,user_address1, long_summary1]) print(id1, title1, publish_time1,user_address1, long_summary1) # 设置文件名称与位置 wb.save("./data/example.xlsx") passif __name__ == "__main__": url = "https://i.news.qq.com/web_feed/getHotModuleList" headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" } for i in range(1,5): print(f"第{i}页") data = { "base_req": { "from": "pc" }, "forward": "2", "qimei36": "0_RpPpK7EBAwAEp", "device_id": "0_RpPpK7EBAwAEp", "flush_num": i, "channel_id": "news_news_top", "item_count": 20 } result = spider(url, headers, data) save_data(result)BeautifulSoup
pip install beautifulsoup4 是一个可以从html与xml文件中提取数据的python库
-
BeautifulSoup(markup, features)解析数据
- markup参数: 要解析的HTML/XML内容
- features参数: 用哪种 HTML/XML 解析器来解析你的内容
from bs4 import BeautifulSoup #导包 # 创建BeautifulSoup对象soup = BeautifulSoup(res.text, 'lxml') # 或使用 # 常用解析器比较 Python内置,无需额外安装soup = BeautifulSoup(res.text, 'html.parser') # 速度快,需要 pip install lxml soup = BeautifulSoup(res.text, 'lxml') # 容错性最好,但速度慢 pip install html5lib soup = BeautifulSoup(res.text, 'html5lib') # 安装对应模块之后BeautifulSoup会自动使用- pip install lxml 是一种使用python编写的解析库, 可以更加迅速, 灵活的处理XML和HTML
方法
find_all(name=None, attrs={}) 用于查找文档中所有符合条件的标签
- name: 标签名
- attrs: 属性
注意: 未查询到返回空列表
find()与find_all()参数相同,但只返回第一个匹配结果, 未查询到返回None
get_text() 获取所有文本(包含子标签文本)
select() 与css选择器(js的query获取dom节点)书写一致,获取的是多个, 未查询到返回空列表
# 选择器示例soup.select('ul') # 所有<ul> ←→ find_all('ul')soup.select('.list') # class="list" ←→ find_all(class_="list")soup.select('#fruits') # id="fruits" ←→ find_all(id="fruits")soup.select('ul#fruits') # id="fruits"的<ul>soup.select('ul > li') # 直接子元素 ←→ find_all('ul').find_all('li', recursive=False)soup.select('ul li:first-child') # 每个<ul>的第一个<li>属性
tag['属性名'] # 不存在会报错tag.attrs['属性名'] # 不存在会报错tag.get("属性名") # 不存在返回Nonetag.attrs # 获取所有属性tag.name # 获取标签名称- .contents 获取标签的所有子级, 返回一个list
- .descendants 获取子孙节点
- .parent 获取父节点
- .next_siblings 后边的所有的兄弟节点
案例
注意: select获取是一个列表,需要通过下标取值
重点: 短时间内一定不要请求次数太多,否则会导致IP地址封禁,(可以通过time设置一下请求的时长)
XPath
XPath 是一种用于在 XML 和 HTML 文档中定位节点的查询语言。相比 BeautifulSoup 的查找方法,XPath 提供了更强大和灵活的定位能力
xpath是操作DOM树
pip install lxml
html文档与xml文档的区别
-
xml用途: 用于存储和传输数据, 其焦点是数据的内容
-
xml标签: 用户自定义,无限扩展
<?xml version="1.0" encoding="UTF-8"?><bookstore> <book category="fiction"> <title>Harry Potter</title> <author>J.K. Rowling</author> <year>2005</year> <price currency="USD">29.99</price> </book> <book category="technology"> <title>Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price currency="EUR">39.95</price> </book></bookstore>
-
-
HTML用途:是显示数据, 数据如何更好看地显示
常用符
| 表达式 | 说明 |
|---|---|
/ |
从根节点选取(绝对路径) |
// |
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(相对路径) |
. |
选取当前节点 |
.. |
选取当前节点的父节点 |
@ |
选取属性 |
| [] | 选择符合条件的节点,使用索引 |
通过以上方式进行获取: 返回一个列表
-
xpath节点.text
- 获取文本内容
-
xpath('/html/body/div/h1/text()')- 通过/text()获取文本内容
通配符与或
XPath 通配符可用来选取未知的 XML 元素。
| 通配符 | 描述 |
|---|---|
| * | 匹配任何元素节点。 |
| @* | 匹配任何属性节点。 |
| node() | 匹配任何类型节点 |
//html/body/div/* # 选择div元素的所有子元素节点//html/body/div/@* # 选择div元素的所有属性/html/body//*[@class] #获取后代具有class类名的元素/html/body/div/node() # 获取div子级的所有节点# | 或tree.xpath('//p[@class="intro"] | //div[@class="content"]')特殊使用
text()="" 匹配文本内容
# 存在空格是无法匹配成功/html/body/a[text()="你好"] # 获取a文字为你好的标签# 清除a标签文字的空格 进行匹配/html/body/div//a[normalize-space(text())="百度"]# 获取对应的属性/html/body/div//a[normalize-space(text())="百度"]/@hrefcontains() 包含
# 获取a包含 文字为百度的标签 存在空格也没事/html/body//a[contains(text(),"百度")]# 获取对应的属性/html/body//a[contains(text(),"百度")]/@href# 获取a标签包含n的类名 标签/html/body//a[contains(@class,"n")]lxml库
import requestsfrom lxml import etreeimport reimport timedef spider(url): global index headers = {} resp = requests.request("GET", url, headers=headers) if resp.status_code == 200: xml = etree.HTML(resp.text) elements = xml.xpath('//div[@class="bot-content"]') page_next = xml.xpath('//*[@id="__layout"]/div/div[3]/div[1]/div[4]/div/div[2]/div/div[3]/a[2]/@href') for ele in elements: href = ele.xpath('./@data-href')[0] price = ele.xpath('./div[@class="price"]//text()')[0] # 获取价格 title = ele.xpath('./div[@class="name-pic-box"]//text()')[0] # 获取价格 spider_msg(href, price, title) index = index + 1 if index < 8: spider(page_next) else: print("请求失败:", resp.status_code) passdef spider_msg(href, price, title): time.sleep(1.5) headers = {} resp = requests.request("GET", href, headers=headers) if resp.status_code == 200: xml = etree.HTML(resp.text) ele = xml.xpath('//div[@class="price-box font12"]/div//text()') result = "".join(ele).strip() result = re.sub(r'\s+', "-", result) with open("./ce.txt", "a", encoding="utf-8") as f: f.write(f'店铺:{title}\n价格:{price}\n时间:{result}\n网址:{href}\n\n')if __name__ == "__main__": url = "https://www.zbj.com/fw/?es=9011" index = 1 spider(url)- 查询属性条件通过[]
xml_doc.xpath('//div[@class="item"]')
- 获取属性值需要通过@
xml_doc.xpath('//div[@class="item"]/div/a/img/@src')
- 通过text()获取内容
xml_doc.xpath('//li/a[@href="link1.html"]/text()')