赞
踩
本阶段课程主要学习获取响应之后如何从响应中提取我们想要的数据,在本阶段课程中我们会讲解一些常用的方法和模块,基本上我们以后遇到的情况在掌握本阶段课程之后都能搞定
在发送请求获取响应之后,可能存在多种不同类型的响应内容;而且很多时候,我们只需要响应内容中的一部分数据
结构化的响应内容
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字符串
要搞清楚html和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内容可以表示为下面的树结构:
二者区别如下图
html:
超文本标记语言
为了更好的显示数据,侧重点是为了显示
xml:
可扩展标记语言
如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的。jsonpath模块就能解决这个痛点,接下来我们就来学习jsonpath模块
jsonpath可以按照key对python字典进行批量数据提取
jsonpath是第三方模块,需要额外安装
pip install jsonpath
from jsonpath import jsonpath
ret = jsonpath(a, 'jsonpath语法规则字符串')
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 } } } from jsonpath import jsonpath print(jsonpath(book_dict, '$..author')) # 如果取不到将返回False # 返回列表,如果取不到将返回False
我们以拉勾网城市JSON文件 [ 为例,获取所有城市的名字的列表,并写入文件。
参考代码:
import requests import jsonpath import json # 获取拉勾网城市json字符串 url = ' headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"} response =requests.get(url, headers=headers) html_str = response.content.decode() # 把json格式字符串转换成python对象 jsonobj = json.loads(html_str) # 从根节点开始,获取所有key为name的值 citylist = jsonpath.jsonpath(jsonobj,'$..name') # 写入文件 with open('city_name.txt','w') as f: content = json.dumps(citylist, ensure_ascii=False) f.write(content)
本阶段课程主要学习获取响应之后如何从响应中提取我们想要的数据,在本阶段课程中我们会讲解一些常用的方法和模块,基本上我们以后遇到的情况在掌握本阶段课程之后都能搞定
对html或xml形式的文本提取特定的内容,就需要我们掌握lxml模块的使用和xpath语法。
XPath (XML Path Language) 是一门在 HTML\XML 文档中查找信息的语言,可用来在 HTML\XML 文档中对元素和属性进行遍历。
W3School官方文档:[
提取xml、html中的数据需要lxml模块和xpath语法配合使用
要想利用lxml模块提取数据,需要我们掌握xpath语法规则。接下来我们就来了解一下xpath helper插件,它可以帮助我们练习xpath语法
在谷歌浏览器中对当前页面测试xpath语法规则
我们以windos为例进行xpath helper的安装
下载Chrome插件 XPath Helper
可以在chrome应用商城进行下载,如果无法下载,也可以从下面的链接进行下载
下载地址:[ 密码:337b
把文件的后缀名crx改为rar,然后解压到同名文件夹中
把解压后的文件夹拖入到已经开启开发者模式的chrome浏览器扩展程序界面
学习xpath语法需要先了解xpath中的节点关系
每个html、xml的标签我们都称之为节点,其中最顶层的节点称为根节点。我们以xml为例,html也是一样的
author
是title
的第一个兄弟节点
- XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。
- 这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
- 使用chrome插件选择标签时候,选中时,选中的标签会添加属性class="xh-highlight"
表达式 | 描述 |
---|---|
nodename | 选中该元素。 |
/ | 从根节点选取、或者是元素和元素间的过渡。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
text() | 选取文本。 |
接下来我们通过itcast的页面来练习上述语法:[
选择所有的h2下的文本
//h2/text()
获取所有的a标签的href
//a/@href
获取html下的head下的title的文本
/html/head/title/text()
获取html下的head下的link标签的href
/html/head/link/@href
可以根据标签的属性值、下标等来获取特定的节点
路径表达式 | 结果 |
---|---|
//title[@lang="eng"] | 选择lang属性值为eng的所有title元素 |
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()>1] | 选择bookstore下面的book元素,从第二个开始选择 |
//book/title[text()='Harry Potter'] | 选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
从itcast的页面中,选择所有学科的名称、第一个学科的链接、最后一个学科的链接:[
所有的学科的名称
//div[@class="nav_txt"]//a[@class="a_gd"]
第一个学科的链接
//div[@class="nav_txt"]/ul/li[1]/a/@href
最后一个学科的链接
//div[@class="nav_txt"]/ul/li[last()]/a/@href
可以通过通配符来选取未知的html、xml的元素
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
node() | 匹配任何类型的节点。 |
从itcast的页面中 [ ,选中全部的标签、全部的属性
全部的标签
//*
全部的属性
//node()
lxml模块是一个第三方模块,安装之后使用
对发送请求获取的xml或html形式的响应内容进行提取
pip/pip3 install lxml
from lxml import etree
html = etree.HTML(text)
ret_list = html.xpath("xpath语法规则字符串")
xpath方法返回列表的三种情况
返回空列表:根据xpath语法规则字符串,没有定位到任何元素
运行下面的代码,查看打印的结果
from lxml import etree text = ''' <div> <ul> <li class="item-1"> <a href="link1.html">first item</a> </li> <li class="item-1"> <a href="link2.html">second item</a> </li> <li class="item-inactive"> <a href="link3.html">third item</a> </li> <li class="item-1"> <a href="link4.html">fourth item</a> </li> <li class="item-0"> a href="link5.html">fifth item</a> </ul> </div> ''' html = etree.HTML(text) #获取href的列表和title的列表 href_list = html.xpath("//li[@class='item-1']/a/@href") title_list = html.xpath("//li[@class='item-1']/a/text()") #组装成字典 for href in href_list: item = {} item["href"] = href item["title"] = title_list[href_list.index(href)] print(item)
将下面的html文档字符串中,将每个class为item-1的li标签作为1条新闻数据。提取a标签的文本内容以及链接,组装成一个字典。
text = ''' <div> <ul>
<li class="item-1"><a>first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul> </div> '''
注意:
先分组,再提取数据,可以避免数据的错乱
对于空值要进行判断
参考代码
from lxml import etree text = ''' <div> <ul> <li class="item-1"> <a href="link1.html">first item</a> </li> <li class="item-1"> <a href="link2.html">second item</a> </li> <li class="item-inactive"> <a href="link3.html">third item</a> </li> <li class="item-1"> <a href="link4.html">fourth item</a> </li> <li class="item-0"> a href="link5.html">fifth item</a> </ul> </div>''' #根据li标签进行分组 html = etree.HTML(text) li_list = html.xpath("//li[@class='item-1']") #在每一组中继续进行数据的提取 for li in li_list: item = {} item["href"] = li.xpath("./a/@href")[0] if len(li.xpath("./a/@href"))>0 else None item["title"] = li.xpath("./a/text()")[0] if len(li.xpath("./a/text()"))>0 else None print(item)
运行下边的代码,观察对比html的原字符串和打印输出的结果
from lxml import etree
html_str = ''' <div> <ul>
<li class="item-1"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul> </div> '''
html = etree.HTML(html_str)
handeled_html_str = etree.tostring(html).decode()
print(handeled_html_str)
打印结果和原来相比:
li
标签html
等标签<html><body><div> <ul>
<li class="item-1"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul> </div> </body></html>
结论:
lxml.etree.HTML(html_str)可以自动补全标签
lxml.etree.tostring
函数可以将转换为Element对象再转换回html字符串
爬虫如果使用lxml来提取数据,应该以lxml.etree.tostring
的返回结果作为提取数据的依据
本阶段课程主要学习selenium自动化测试框架在爬虫中的应用,selenium能够大幅降低爬虫的编写难度,但是也同样会大幅降低爬虫的爬取速度。在逼不得已的情况下我们可以使用selenium进行爬虫的编写。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。