标题无心冒犯,就是以为这个广告挺好玩的html
前期回顾:你要偷偷学Python(第十三天)python
今天咱们来看别人口中“永远滴神” – Xpath网络
我也不知道为何被称做永远滴神,可是我知道确定不是由于它难。app
插播一条推送:(若是是小白的话,能够看一下下面这一段)编辑器
我建了一个Python学习答疑群,有兴趣的朋友能够了解一下:若是你们在学习中遇到困难,想找一个python学习交流环境,能够加入咱们的python圈,裙号1160381299,可领取python学习资料,会节约不少时间,减小不少遇到的难题。函数
本系列文默认各位有必定的C或C++基础,由于我是学了点C++的皮毛以后入手的Python。工具
本系列文默认各位会百度,学习‘模块’这个模块的话,仍是建议你们有本身的编辑器和编译器的,上一篇已经给你们作了推荐啦?学习
而后呢,本系列的目录嘛,说实话我我的比较倾向于那两本 Primer Plus,因此就跟着它们的目录结构吧。测试
本系列也会着重培养各位的自主动手能力,毕竟我不可能把全部知识点都给你讲到,因此本身解决需求的能力就尤其重要,因此我在文中埋得坑请不要把它们当作坑,那是我留给大家的锻炼机会,请各显神通,自行解决。url
咱们刚开始接触Xpath是何时?对,selenium的时候,那时候咱们抓不下标签,就转方向从Xpath入手。
那么这个Xpath究竟是个什么东西居然如此的神通广大?
XPath即为XML路径语言(XML Path Language),它是一种用来肯定XML文档中某部分位置的语言。
也很少哔哔,就知道Xpath是网页内容的导航就好。
如下内容部分出自百度百科,截取适用于爬虫的部分。
毕竟人家都整理好了,咱也难出其右。
选取节点 XPath 使用路径表达式在 XML 文档中选取节点。节点是经过沿着路径或者 step 来选取的。 [1]
下面列出了最有用的路径表达式:
找的时候是一篇伪代码,我作了微调,加了点注释。
也能够本身去调试一遍,本身动手的话印象会比较深入。
# element tree: 文档树对象
import requests
from lxml import etree
# 爬取百度贴吧数据
class Tieba(object):
def __init__(self,key):
self.url = "https://tieba.baidu.com/"+key #动态url,理论上能够获取任一贴吧的网页
#print(self.url)
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
}
# 获取数据
def get_data(self, url):
response = requests.get(url, headers=self.headers)
return response.content #以二进制形式返回(大能够用text去试一下,返回文本形式)
# 数据提取
def parse_data(self, data):
# 解码,并删除源代码中的注释
data = data.decode().replace("<!--", "").replace("-->", "")
# 建立element对象
html = etree.HTML(data)
# 根据xpath语法提取每页标题对象的贴吧标题xpath对象
# 关于这个xpath是如何肯定的,代码后面会放上一张图,本身悟一下
el_list = html.xpath("//li[@class=' j_thread_list clearfix']/div/div[2]/div[1]/div[1]/a")
print(el_list)
# 遍历每页的贴吧标题xpath对象
data_list = []
for el in el_list:
# 根据每一个xpath对象获取每一个标题的titile属性和link属性
temp = {}
temp["title"] = el.xpath("./text()")[0] #取第一个文本
temp["link"] = "http://tieba.baidu.com" + el.xpath("./@href")[0] #同
# 将每一个标题属性字典添加到列表中
data_list.append(temp)
# 获取下一页url
try:
next_url = "https:" + html.xpath('//a[contains(text(),"下一页>")]/@href')[0] #contains()函数,后面讲
except:
next_url = None
# 返回每页的标题属性字典和下一页的url
return data_list, next_url
# 保存 伪代码
def save_data(self, data_list):
for data in data_list:
print(data)
# 运行
def run(self):
# 第一次的url是self.url
next_url = self.url
# 实现翻页 直到next_url == None 结束翻页
while True:
# 发送请求,获取响应
data = self.get_data(next_url)
# 从响应中提取数据(数据和翻页用的url)
data_list, next_url = self.parse_data(data)
self.save_data(data_list)
print(next_url)
# 判断是否结束
if next_url == None:
break
if __name__ == '__main__':
tieba = Tieba("f?kw=王者荣耀")
tieba.run() #函数入口
如下皆为伪代码,测试文件木有,留着当工具书使用
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="www.baidu.com">baidu</a>
<li class="item-1"><a href="https://blog.csdn.net/qq_25343557">myblog</a>
<li class="item-2"><a href="https://www.csdn.net/">csdn</a>
<li class="item-3"><a href="https://hao.360.cn/?a1004">hao123</a>
'''
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('UTF-8'))
html = etree.parse('./test.html',etree.HTMLParser())
result = html.xpath('//*')#'//'表示获取当前节点子孙节点,'*'表示全部节点,'//*'表示获取当前节点下全部节点
for item in result:
print(item)
result = html.xpath('//li')#将*改成li,表示只获取名称为li的子孙节点
#返回一个列表
for item in result:
print(item)
result = html.xpath('//li/a')#//li选择全部的li节点,/a选择li节点下的直接子节点a
for item in result:
print(item)
咱们也可使用//ul//a首先选择全部的ul节点,再获取ul节点下的的全部a节点,最后结果也是同样的。可是使用//ul/a就不行了,首先选择全部的ul节点,再获取ul节点下的直接子节点a,然而ul节点下没有直接子节点a,固然获取不到。须要深入理解//和/的不一样之处。/用于获取直接子节点,//用于获取子孙节点。
根据XPath经常使用规则能够经过@匹配指定的属性。咱们经过class属性找最后一个li节点。
result = html.xpath('//li[@class="item-3"]')#最后一个li的class属性值为item-3,返回列表形式
print(result)
根据XPath经常使用规则能够经过…获取当前节点的父节点。如今我要获取最后一个a节点的父节点下的class属性。
result = html.xpath('//a[@href="https://hao.360.cn/?a1004"]/../@class')
#a[@href="https://hao.360.cn/?a1004"]:选择href属性为https://hao.360.cn/?a1004的a节点
#..:选取父节点
#@class:选取class属性,获取属性值
print(result)
不少时候咱们找到指定的节点都是要获取节点内的文本信息。咱们使用text()方法获取节点中的文本。如今获取全部a标签的文本信息。
result = html.xpath('//ul//a/text()')
print(result)
在上面的例子中全部的属性值都只有一个,若是属性值有多个还能匹配的上吗?(上面代码里面翻页看不懂的注意了啊)
遇到属性值有多个的状况咱们须要使用contains()函数了,contains()匹配一个属性值中包含的字符串 。包含的字符串,而不是某个值。
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="www.baidu.com">baidu</a>
<li class="spitem-1"><a href="https://blog.csdn.net/qq_25343557">myblog</a>
<li class="item-2"><a href="https://www.csdn.net/">csdn</a>
<li class="item-3"><a href="https://hao.360.cn/?a1004">hao123</a>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class,"item-0") and @name="one"]/a/text()')#使用and操做符将两个条件相连。
print(result)
也许你会说这个直接使用name的属性值就能够获得了,然而,这里只是做为演示。
在上面的操做中我屡次找第2个li节点或找最后一个li节点,使用属性值进行匹配。其实何须呢!咱们能够根据顺序进行选择。
result = html.xpath('//li[2]/a/text()')#选择第二个li节点,获取a节点的文本
result = html.xpath('//li[last()]/a/text()')#选择最后一个li节点,获取a节点的文本
result = html.xpath('//li[last()-1]/a/text()')#选择倒数第2个li节点,获取a节点的文本
result = html.xpath('//li[position()<=3]/a/text()')#选择前三个li节点,获取a节点的文本
函数太多了,感受我这里的函数知足不了你的话能够移步:https://www.w3school.com.cn/xpath/index.asp
咱们能够经过XPath获取祖先节点,属性值,兄弟节点等等,这就是XPath的节点轴。轴可定义相对于当前节点的节点集。
result = html.xpath('//li[1]/ancestor::*')
#ancestor表示选取当前节点祖先节点,*表示全部节点。合:选择当前节点的全部祖先节点。
result = html.xpath('//li[1]/ancestor::div')
#ancestor表示选取当前节点祖先节点,div表示div节点。合:选择当前节点的div祖先节点。
result = html.xpath('//li[1]/ancestor-or-self::*')
#ancestor-or-self表示选取当前节点及祖先节点,*表示全部节点。合:选择当前节点的全部祖先节点及本及自己。
result = html.xpath('//li[1]/attribute::*')
#attribute表示选取当前节点的全部属性,*表示全部节点。合:选择当前节点的全部属性。
result = html.xpath('//li[1]/attribute::name')
#attribute表示选取当前节点的全部属性,name表示name属性。合:选择当前节点的name属性值。
result = html.xpath('//ul/child::*')
#child表示选取当前节点的全部直接子元素,*表示全部节点。合:选择ul节点的全部直接子节点。
result = html.xpath('//ul/child::li[@name="two"]')
#child表示选取当前节点的全部直接子元素,li[@name="two"]表示name属性值为two的li节点。合:选择ul节点的全部name属性值为two的li节点。
result = html.xpath('//ul/descendant::*')
#descendant表示选取当前节点的全部后代元素(子、孙等),*表示全部节点。合:选择ul节点的全部子节点。
result = html.xpath('//ul/descendant::a/text()')
#descendant表示选取当前节点的全部后代元素(子、孙等),a/test()表示a节点的文本内容。合:选择ul节点的全部a节点的文本内容。
result = html.xpath('//li[1]/following::*')
#following表示选取文档中当前节点的结束标签以后的全部节点。,*表示全部节点。合:选择第一个li节点后的全部节点。
result = html.xpath('//li[1]/following-sibling::*')
#following-sibling表示选取当前节点以后的全部同级节点。,*表示全部节点。合:选择第一个li节点后的全部同级节点。
result = html.xpath('//li[1]/parent::*')
#选取当前节点的父节点。父节点只有一个,祖先节点可能多个。
result = html.xpath('//li[3]/preceding::*')
#preceding表示选取文档中当前节点的开始标签以前的全部同级节点及同级节点下的节点。,*表示全部节点。合:选择第三个li节点前的全部同级节点及同级节点下的子节点。
result = html.xpath('//li[3]/preceding-sibling::*')
#preceding-sibling表示选取当前节点以前的全部同级节点。,*表示全部节点。合:选择第三个li节点前的全部同级节点。
result = html.xpath('//li[3]/self::*')
#选取当前节点。
弄完这个,接下来就试试看能不能用Xpath将腾讯校园招聘网的数据抓取下来整理起来咯。
最后多说一句,想学习Python可联系小编,这里有我本身整理的整套python学习资料和路线,想要这些资料的均可以进q裙1160381299领取。
本文章素材来源于网络,若有侵权请联系删除。