2022。2.22 更新
你用 selenium
抓取,必定有 body
你用 requests
抓取,不一定有 body
浏览器会对不存在 body
的情况自动加上 body
所以,你用 requests
抓取就去分析 html tree
用 selenium
就去分析 render tree
html tree
就是networks
标签中的html
内容;render tree
就是Elements
标签页中的内容
2020.7.15更新
以前的讲法有点问题,所以再次更新一下,也算是填坑
定位不到tbody是因为标准差异,tbody不是必须存在的
chrome的Elements标签页的tbody是肯定存在的
但是程序员写的网页不一定会有tbody
但是在chrome的Elements标签页不管返回的html有没有tbody,chrome都会有(有就不加,没有就自动加上)
所以
用selenium请求网页数据,就加上tbody标签,因为selenium返回的必定是包含tbody的(因为返回的是chrome的Elements标签页的内容)
用requests请求的时候,就自己看看源html内是否真的包含tbody标签(可以在chrome的network标签页下查看)
总结:服务器返回的html不一定有tbody标签(具体看网站前端程序员有没有加tbody标签),但是经过chrome渲染的render html必定包含tbody标签(服务器返回没有的话,浏览器就给你自动加上)
以下是原文:
写于2019.10.29日
测试库:lxml库;链接链接:http://www.sxchxx.com/index-13-1075-1.html
问题发现
个人比较喜欢用xpath解析网页,但时常得到的结果却是一个空列表。
1.1 etree.HTML
from lxml import etree
import requests
url = 'http://www.sxchxx.com/index-13-1075-1.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36',
}
resposne = requests.get(url, headers=headers)
parser = etree.HTMLParser(encoding="utf-8")
html = etree.HTML(resposne.text, parser=parser)
resu=html.xpath('//*[@id="large_mid"]/table[2]/tr[3]/td/p//text()')
print(resu)
当用如上代码解析如下网页时,可以获取正文
但发现我们并没有在rule里面加入tbody标签。相反,加入tbody标签会使的解析结果变成一个空列表
html.xpath('//*[@id="large_mid"]/table[2]/tbody/tr[3]/td/p//text()') # 这样会得到空列表
1.2 etree.parse
使用etree.parse和etree.HTML恰好相反
from lxml import etree
import requests
parser = etree.HTMLParser(encoding="utf-8")
html = etree.parse('test.html', parser=parser)
content = html.xpath('//*[@id="large_mid"]/table[2]/tbody/tr[3]/td/p//text()')
print(content)
将网页保存成test.html,再用etree.parse加载,发现rule中加入tbody标签才能获得预期的结果;不加tbody标签会获得一个空列表
1.3 代码对比
from lxml import etree
import requests
parser = etree.HTMLParser(encoding="utf-8")
html = etree.parse('test.html', parser=parser)
content = html.xpath('//*[@id="large_mid"]/table[2]/tbody/tr[3]/td/p//text()')
print(content)
print('----------------分割线-------------------')
url = 'http://www.sxchxx.com/index-13-1075-1.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36',
}
resposne = requests.get(url, headers=headers)
parser = etree.HTMLParser(encoding="utf-8")
html = etree.HTML(resposne.text, parser=parser)
content = html.xpath('//*[@id="large_mid"]/table[2]/tr[3]/td/p//text()')
print(content)
解决问题
2.1曲线救国
如果解析在线网页,不要添加tbody标签
反则解析本地(离线)网页,添加tbody标签
2.2其他方法
请看下面的原因分析
问题发生的原因
对比上面两种方法,差异在于html = etree.parse('test.html', parser=parser)
html = etree.HTML(resposne.text)
这两行代码
而解析器是相同的parser = etree.HTMLParser(encoding="utf-8")
因此,我猜测,可能是parse或者HTML对代码做了某种“格式化”调整。
貌似lxml这个库使用其他语言编写,看不到源代码,无法从源代码下手检查
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。