获取页面内容除使用正则意外,还可以使用XPath,其原理是将html代码转换为xml格式,然后使用XPath查找html节点或元素。
选取节点
XPath使用路径表达式来选取XML文档中的节点或节点集。
常用的路径表达式见下表:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,不考虑其是否为子级 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
谓语
谓语用来查找某个特定的节点或者包含某个指定的值得节点,被嵌在方括号中。
路径表达式 | 释义 |
---|---|
/one/two[1] | 选取属于one子元素的第一个two元素 |
/one/two[last()] | 选取属于one子元素的最后一个two元素 |
/one/two[last()-1] | 选取属于one子元素的倒数第二个two元素 |
/one/two[position()<3] | 选取最前面的两个属于one元素的子元素two元素 |
//one[@lang] | 选取所有拥有名为lang的属性的one元素 |
//one[@lang='test'] | 选取所有拥有值为test的lang属性的one元素 |
/one/two[position>10] | 选取one元素的所有two元素,且其中position属性的值大于10 |
选取未知节点
通配符 | 描述 |
---|---|
* | 匹配如何元素节点 |
@* | 匹配任何属性节点 |
node() | 匹配任何类型节点 |
例:
路径表达式 | 结果 |
---|---|
/one/* | 选取one中所有的子元素 |
//* | 选取文档中的所有元素 |
//one[@*] | 选取所有带有属性的one元素 |
选取若干路径
可以使用管道符“|”选取若干个路径,相当于或
XPath运算符
运算符 | 描述 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
div | 除法 |
= | 等于 |
!= | 不等于 |
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
or | 或 |
and | 与 |
mod | 计算余数 |
XPath的使用
from lxml.html import etree # 获取到的要匹配的html字符串 html = '' content = etree.HTML(html) # 返回所有匹配成功的列表集合 res = content.xpath('表达式')
BeautifulSoup4的使用
和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
想使用BeautifulSoup4首先需要安装,执行pip install beautifulsoup4
安装,BeautifulSoup4的使用方法如下
from bs4 import BeautifulSoup html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ soup = BeautifulSoup(html, 'lxml') # 打开本地Html文件创建对象 # soup = BeautifulSoup(open('xxx.html')) print(soup.prettify()) # 获取标签 soup.title # 获取title soup.p # 获取p标签 soup.a # 获取a标签 print(soup.name) # [document] #soup 对象本身比较特殊,它的 name 即为 [document] print(soup.head.name) # head #对于其他内部标签,输出的值便为标签本身的名称 print(soup.p.attrs) # {'class': ['title'], 'name': 'dromouse'} # 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。 print(soup.p['class']) # soup.p.get('class') # ['title'] #还可以利用get方法,传入属性的名称,二者是等价的 soup(p['class']) = "newClass" print(soup.p) # 可以对这些属性和内容等等进行修改 # <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p> del(soup.p['class']) # 还可以对这个属性进行删除 print (soup.p) # <p name="dromouse"><b>The Dormouse's story</b></p> # 获取标签内文字 print(soup.p.string) # tag 的 .content 属性可以将tag的子节点以列表的方式输出 print(soup.head.contents) # [<title>The Dormouse's story</title>] # .children它返回的不是一个 list(是一个列表生成器),不过我们可以通过遍历获取所有子节点。 print(soup.head.children) # <list_iterator object at 0x000002B9D7E4CFD0> # .descendants 获取所有子孙节点 print(soup.descendants) # 结果是一个生成器 <generator object Tag.descendants at 0x0000020AAC5B1B10>
BeautifulSoup4的搜索
# 使用find_all(name, attrs, recursive, text, **kwargs)查找 # 传入name参数 soup.find_all('p') # 查找所有p标签 soup.find_all('a') # 查找所有a标签 soup.find_all(re.compile('^p')) # 使用正则查找所有以p打头的标签 soup.find_all(['p', 'a']) # 传入列表,查找所有p和a标签 # 传入attrs参数 soup.find_all(id='link1') # 查找所有id未link1的标签,通过标签属性查找的方式适用大多数标签属性,包括id,style,title,但有 “-”,Class标签属性例外。 soup.find_all(attrs={'class': 'sister'}) # 传入text参数 soup.find_all(text="Lacie") # 产找所有含有内容为Lacie的对象 soup.find_all(text=['aaa', 'bbb']) soup.find_all(text=re.compile("Tit")) # 传入正则匹配 # css选择查找 soup.select('title') # 根据标签查找 soup.select('#link1') # 根据Id查找 soup.select('.sister') # 根据类名查找 soup.select('p #link1') # 组合查找 soup.select("head > title") # 查找子标签 soup.select('a[class="sister"]') # 属性查找 soup.select('title')[0].get_text() # 使用get_text获取内容
实例
from bs4 import BeautifulSoup from urllib.request import * import json def tencent(): url = 'https://hr.tencent.com' header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"} request = Request(url + '/position.php?&start=0#a', headers=header) response = urlopen(request) html = response.read() # with open('html.txt', 'wb+') as f: # f.write(html) soup = BeautifulSoup(html, 'lxml') result = soup.select('tr[class="even"]') result2 = soup.select('tr[class="old"]') result.extend(result2) items = [] for site in result: item = {} item['name'] = site.select('td a')[0].get_text() item['link'] = site.select('td a')[0].attrs['href'] item['category'] = site.select('td')[1].get_text() item['recruitNumber'] = site.select('td')[2].get_text() item['workLocation'] = site.select('td')[3].get_text() item['publishTime'] = site.select('td')[4].get_text() items.append(item) line = json.dumps(items, ensure_ascii=False) with open('html.txt', 'w') as f: f.write(line) if __name__ == "__main__": tencent()
来源:https://www.cnblogs.com/peilanluo/p/10311827.html