3. 数据提取方法
3.1数据提取的概念和数据的分类
在爬虫爬取的数据中有很多不同类型的数据,我们需要了解数据的不同类型来又规律的提取和解析数据.
- 结构化数据:json,xml等 【前后端分离】
- 处理方式:直接转化为python类型
- 非结构化数据:HTML 【前后端不分离】
- 处理方式:正则表达式、xpath
3.2 快速辨别数据类型
- 数据类型判别,看第一条发出的请求的响应,这条由我们向浏览器发出的请求是最干净的,其他的数据请求都是由浏览器帮我们发出的。
- 第一条请求的视图,数据已经渲染上去,很明显的就是后端模板渲染好才返回整个页面的前后端不分离非结构化数据。
3.3 结构化数据类型的提取
- 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>
1. json的数据提取
-
python 内置有一个标准库叫 JSON 库 ,可以实现 JSON 字符串与字典之间的转换
-
之前的案例中和练习中已经有大量的演示,提取时,现将 JSON 字符串处理【切片】成一个标准的字符串
然后用 json.loads() 转化为列表或者字典 , 然后进行需要的数据解析提取,随后将提取的数据,再封装成字典或者列表,随后可以通过 json.dumps() 方法转化为字符串通过文件进行保存, 或者根据需要存入数据库中。
2. jsonpath模块的学习
2.1 jsonpath介绍
用来解析多层嵌套的json数据;JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, PHP 和 Java。
2.2 JsonPath 的安装与语法
pip install jsonpath # 安装
官方文档:http://goessner.net/articles/JsonPath
JSONPath 语法:
2.3 案例解析
{ "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
}
}
}
JSONPath | Result |
---|---|
$.store.book[*].author | store中的所有的book的作者 |
$..author | 所有的作者 |
$.store.* | store下的所有的元素 |
$.store..price | store中的所有的内容的价格 |
$..book[2] | 第三本书 |
$..book[(@.length-1)] | $..book[-1:] |
$..book[0,1] | $..book[:2] |
$..book[?(@.isbn)] | 获取有isbn的所有数 |
$..book[?(@.price<10)] | 获取价格大于10的所有的书 |
$..* | 获取所有的数据 |
案例6
目标URL: https://www.lagou.com/lbs/getAllCitySearchLabels.json
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/15 14:54
# @Author : GHong
import requests
import jsonpath
from json import loads
url = "https://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"
}
response = requests.get(url, headers=headers)
data_dict = loads(response.content.decode()) # 转换成字典类型
# 通过结构分析我们想要获取所有城市的名称
# 这个数据在content=>data=>allCitySearchLabels=>A,B,C,D,E,F...=>[]["name"]
"""
方案一:不使用JsonPath 模块
"""
# node = data_dict["content"]["data"]["allCitySearchLabels"]
#
# upper = list(map(chr, range(65, 91))) # 快速生成大写字母表
#
# for i in upper:
# try:
# for item in node[i]:
# print(item["name"])
# except:
# print("没有以%s开头的城市" % i)
"""使用Jsonpath模块"""
for item in jsonpath.jsonpath(data_dict, "$..name"):
print(item)
练习5 (3.5星)
爬取豆瓣上所有的 (国产剧,英美剧,动漫,韩剧,日剧,综艺的 【片名,评分及链接】)
参考答案 提取码:b8ml
3.4 非结构化数据提取
1. 正则提取法
1 .1什么是正则表达式
用事先定义好的一些特定字符、及这些特定字符的组合,组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑。
1.2 正则表达式的语法
知识点
- 正则中的字符
- 正则中的预定义字符集
- 正则中的数量词
1.3 re模块常见方法
-
pattern.match(从头找一个)
-
pattern.search(找一个)
-
pattern.findall(找所有)
- 返回一个列表,没有就是空列表
re.findall("\d","chuan1zhi2") >> ["1","2"]
-
pattern.sub(替换)
re.sub("\d","_","chuan1zhi2") >> ["chuan_zhi_"]
-
re.compile(编译)
-
返回一个模型P,具有和re一样的方法,但是传递的参数不同
-
匹配模式需要传到compile中
p = re.compile("\d",re.S) p.findall("chuan1zhi2")
-
1.4 匹配中文
在某些情况下,我们想匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围 主要在 [u4e00-u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。
import re
str = "你好呀,ha杀ki"
print(re.findall(r'[\u4e00-\u9fa5]+', str))
1.5 正则实战
目标URL:http://www.chinanews.com/
import re
import requests
url = "http://www.chinanews.com/"
response = requests.get(url)
# print(response.content.decode())
txt = response.content.decode()
# 通过观察我们发现目标数据结构 :
"""
<img width="320" height="270" src="/part/home2013/451/U179P4T451D5F17256DT20200815171855.jpg" alt="乌鲁木齐社区做好居民服务">
"""
nodes = re.findall(r'<img width="320" height="270" src="(.*?)"', txt)
for node in nodes:
print(url + node)
3.5. Xpath 提取
- 一般情况下非结构化的数据我们都会用Xpath来提取,正则匹配效率低,且步骤较为繁杂
- 了解 html和xml的区别
- 掌握 xpath获取节点属性的方法
- 掌握 xpath获取文本的方法
- 掌握 xpath查找特定节点的方法
1 为什么要学习xpath和lxml
lxml是一款高性能的 Python HTML/XML 解析器,我们可以利用XPath,来快速的定位特定元素以及获取节点信息
2 什么是xpath
XPath (XML Path Language) 是一门在 HTML\XML 文档中查找信息的语言,可用来在 HTML\XML 文档中对元素和属性进行遍历。
W3School官方文档:http://www.w3school.com.cn/xpath/index.asp
3.了解xml (已淘汰,仅存部分配置文件有应用)
xml使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然可扩展标记语言占用的空间比二进制数据要占用更多的空间,但可扩展标记语言极其简单易于掌握和使用。
4.xpath的节点关系
知识点:
- 认识xpath中的节点
- 了解xpath中节点之间的关系
4.1 xpath中的节点是什么
每个XML的标签我们都称之为节点,其中最顶层的节点称为根节点。
5 xpath中节点选择的工具
- Chrome插件 XPath Helper
- 下载地址:链接:https://pan.baidu.com/s/1psnkF25EkxsfsZjz5wLHdQ 提取码:79fq
- Firefox插件 XPath Checker
注意: 这些工具是用来学习xpath语法的,他们都是从elements中匹配数据,elements中的数据和url地址对应的响应不相同,所以在代码中,不建议使用这些工具进行数据的提取
Xpath Helper 快捷键 ctrl + shift +alt +x 【激活Xpath窗口】
6.1 选取节点
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
使用chrome插件选择标签时候,选中时,选中的标签会添加属性class="xh-highlight"
下面列出了最有用的表达式:
表达式 | 描述 |
---|---|
nodename | 选中该元素。 |
/ | 从根节点选取、或者是元素和元素间的过渡。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
text() | 选取文本。 |
实例
目标URL: http://www.jokeji.cn/jokehtml/%E5%86%B7%E7%AC%91%E8%AF%9D/2020080419273330.htm
- 一般数据提取为 json 或者 Xpath
3.6 lxml模块
- 应用 lxml库提取数据方法
- 了解 lxml对数据处理和提取之后的数据类型
- 了解 lxml把element转化为字符串的方法
在前面学习了xpath的语法,那么在python爬虫代码中我们如何使用xpath呢? 对应的我们需要lxml
1 lxml的安装
pip install lxml
2 lxml的使用
2.1 lxml模块的入门使用
-
导入lxml 的 etree 库 (导入没有提示不代表不能用)
from lxml import etree
-
利用etree.HTML,将字符串转化为Element对象,Element对象具有xpath的方法,返回结果的列表,能够接受bytes类型的数据和str类型的数据
html = etree.HTML(text) ret_list = html.xpath("xpath字符串")
-
把转化后的element对象转化为字符串,返回bytes类型结果
etree.tostring(element)
假设我们现有如下的html字符换,尝试对他进行操作
案例7
目标URL: http://www.jokeji.cn/jokehtml/%E5%86%B7%E7%AC%91%E8%AF%9D/2020080419273330.htm
爬取十页冷笑话
//span[@id='text110']/p
//div[@class='zw_page1']/a
import requests
from lxml import etree
"""jokehtml/冷笑话/2020080419273330.htm""" # 头页结点
class Joke:
def __init__(self):
self._count = 1
def get(self, url, page):
self._url = "http://www.jokeji.cn/" + url # 拼接组建新页的URL
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",
"Referer": "http://www.jokeji.cn/list43_1.htm"
}
response = requests.get(self._url, headers)
self.analytical(response, page)
def analytical(self, response, page):
html = etree.HTML(response.content.decode("gbk"))
if self._count < page:
self._count += 1
node = html.xpath("//div[@class='zw_page1']/a/@href")[0][5:] # 提取下一页的url节点
self.get(node, page)
jokes = html.xpath("//span[@id='text110']/p/text()") # 解析笑话节点
for joke in jokes:
print(joke)
print("===" * 15)
if __name__ == '__main__':
joke = Joke()
joke.get("jokehtml/冷笑话/2020080419273330.htm", 10)
练习6
百度音乐【千千音乐】 https://music.taihe.com/
要求输入歌手名字即可返回其的歌曲,及链接(4 星)
参考答案 提取码:2pfv
4. 总结
- 到此为止爬虫入门的所有内容就学完了
- 最后一个练习中所用的知识,几乎贯穿了整个爬虫开发流程的知识点
"""
本次练习比较复杂,没有加入翻页功能,翻页的URL在JS里边,需要对网站JS代码进行进一步的剖析
涉及知识点:
1.reuqests的使用,headers、params参数等
2.用户ip代理
3.多种反反爬手段
4.Json数据提取 json结构分析
5.Xpath数据提取 xpath数据定位
6.jsonpath模块的使用
7.lxml模块的使用
8.retrying模块的使用
9.文件的读写
10.系统操作
"""
- 至此已经可以爬取web上的70%左右的数据
- 后边还有进阶内容爬虫性能提升:
- 多线程爬虫,多进程爬虫
- 自动化无头浏览器 selenium 模块
- 打码平台、验证码识别、滑块验证码等
- 爬虫的反反爬策略,js解析等
- Scrapy爬虫框架
- Scrapy-redis 分布式
- 爬虫部署上线
- 爬虫 + 数据分析 + Web 开发一体化【数据可视化】 echarts模块等
(博主能力有限,如有错误的地方,欢迎批评指正,欢迎大家点击关注,以防错过最新内容)