Python实用小技巧
1. Xpath中string的用法以及与text的区别
Xpath提取数据的时候,最常使用的就是Xpath的text()方法,该方法可以提取当前元素的信息,但是某些元素下包含很多嵌套元素,想一并的提取出来,这时候就用到了string(.)方法。
from lxml import etree
s = """
<div>
<ul class="show">这里是show
<li>275万购昌平邻铁三居 总价20万买一居</li>
<li>00万内购五环三居 140万安家东三环</li>
<li>北京首现零首付楼盘 53万购东5环50平</li>
<li>京楼盘直降5000 中信府 公园楼王现房</li>
</ul>
</div>
"""
html = etree.HTML(s)
result = html.xpath("//div/ul[@class='show']")[0]
print(result.xpath('string(.)'))
print('--------------------------------------')
print(result.text)
使用string(.)会把当前节点下面的所有文本都提取出来,这种提取是无视层级的。text就只能提取当前节点的文本,后代节点的文本是无法获取到的。
2. Xpath中路径表达式
/div -------> 从根节点开始选取div节点
//a --------> 选取文档中所有a节点,不考虑其位置
@class --------> 选取名为class的属性
. ------------> 选取当前节点
.. -------------> 选取父节点
/div/p ------------> 从根节点开始选取div节点下的p节点
/div/p[2]/ul -------------> 从根节点开始选取div节点下的的二个p节点下的ul节点
//div[@class=‘text’] ---------------------> 选取所有class属性名为text的div节点
//* ---------------> 选取文档中所有元素
//@* ---------------> 选取文档中所有带属性的元素
: ------------------> 命名空间分隔符;将命名空间前缀与元素名或属性名分隔。
() ------------------> 括号运算符(优先级最高),强制运算优先级。
[] --------------------> 应用筛选模式(即谓词,包括"过滤表达式"和"轴(向前/向后)")。
| ---------------------->两个节点集合的联合,如://messages/message/to | //messages/message/cc
3. Xpath中常用函数介绍
from lxml import etree
s = """
<div>
<ul class="show">这里是show
<li>275万购昌平邻铁三居 总价20万买一居</li>
<li>00万内购五环三居 140万安家东三环</li>
<li>北京首现零首付楼盘 53万购东5环50平</li>
<li>京楼盘直降5000 中信府 公园楼王现房</li>
</ul>
<ul class='ul1'>1</ul>
<ul class='stea'>2</ul>
<ul class='test'>Hello djksladjfkljlasdjflasjkdlflasdlk</ul>
<ul class='all4'>ajsdkfjksldadkfasjHellojflladkfjaklds</ul>
<ul></ul>
<ul></ul>
<ul></ul>
</div>
"""
html = etree.HTML(s)
# starts-with:匹配以为xx开头的东西
# 案例:匹配以s开头的作为类名的元素
result = html.xpath('//div/ul[starts-with(@class,"s")]')
print(result)
# not:匹配不包含某个属性的元素
# 案例:匹配不包含类名的元素
result = html.xpath('//div/ul[not(@class)]')
print(result)
# concat:字符串连接
# 案例:拼接两个元素的内容
result = html.xpath('concat(//div/ul[@class="ul1"]/text(),//div/ul[@class="stea"]/text())')
print(result)
# contains 判断是否含有某个内容
# 案例:获取文本中包含了Hello的元素
result = html.xpath('//div/ul[contains(text(),"Hello")]')
print(result)
4. urllib的自动编码转化
import urllib.request
from io import BytesIO
import gzip
import re
def auto_charset(response):
"""
:param response: 传入响应的结果,自动进行编码转化
:return: 转化好后的网页
"""
# 查看请求头
# print(response.headers)
encoding = response.headers.get('Content-Encoding')
if encoding and "gzip" in encoding: # 如果是gzip格式,就解压转化成正常格式
f = gzip.GzipFile(fileobj=BytesIO(resp.read()))
return f.read().decode('utf-8')
elif response.headers.get("Content-Type") and 'charset' in response.headers.get(
"Content-Type"): # 如果charset在Content-type里面
# 获取网页判断,网页编码通常放在Content-Type的charset里面,获取到这个之后就知道网页采用的编码了,
# 然后就可以使用对应的编码进行解码,这里使用正则进行提取
charset = response.headers.get("Content-Type")
charset = re.search(r'charset=(.+?)(;|$)', charset).group(1)
return response.read().decode(charset)
else: # 如果charset里面没有编码,默认使用utf-8进行编码
# 提取读取获取出来的内容
text = response.read()
# 加入异常处理,如果默认UTF-8编码无法解码,则切换至GBK编码进行转化
try:
return text.decode('utf-8')
except UnicodeDecodeError as e:
return text.decode('gbk')
# 这里切换URL地址
url = 'https://www.biqooge.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Edg/91.0.864.59',
}
# 添加请求头操作
request = urllib.request.Request(url, headers=headers)
resp = urllib.request.urlopen(request)
print(auto_charset(resp))