为什么这个XPath不起作用?

spe*_*ekr 0 html python xpath lxml

我正试图获得股票的公司名称,行业和行业.我下载的HTML 'https://finance.yahoo.com/q/in?s={}+Industry'.format(sign),然后尝试用解析它.xpath()lxml.html.

要获取我正在尝试抓取的数据的XPath,我会转到Chrome中的网站,右键单击该项目,单击Inspect Element,右键单击突出显示的区域,然后单击Copy XPath.这在过去一直对我有用.

可以使用以下代码重现此问题(我使用Apple作为示例):

import requests
from lxml import html

page_p = 'https://finance.yahoo.com/q/in?s=AAPL+Industry'
name_p = '//*[@id="yfi_rt_quote_summary"]/div[1]/div/h2/text()'
sect_p = '//*[@id="yfncsumtab"]/tbody/tr[2]/td[1]/table[2]/tbody/tr/td/table/tbody/tr[1]/td/a/text()'
indu_p = '//*[@id="yfncsumtab"]/tbody/tr[2]/td[1]/table[2]/tbody/tr/td/table/tbody/tr[2]/td/a/text()'

page = requests.get(page_p)
tree = html.fromstring(page.text)

name = tree.xpath(name_p)
sect = tree.xpath(sect_p)
indu = tree.xpath(indu_p)

print('Name: {}\nSector: {}\nIndustry: {}'.format(name, sect, indu))
Run Code Online (Sandbox Code Playgroud)

这给出了这个输出:

Name: ['Apple Inc. (AAPL)']
Sector: []
Industry: []
Run Code Online (Sandbox Code Playgroud)

它没有遇到任何下载困难,因为它能够检索name,但其他两个不起作用.如果我分别用tr[1]/td/a/text()和替换它们的路径tr[1]/td/a/text(),它会返回:

Name: ['Apple Inc. (AAPL)']
Sector: ['Consumer Goods', 'Industry Summary', 'Company List', 'Appliances', 'Recreational Goods, Other']
Industry: ['Electronic Equipment', 'Apple Inc.', 'AAPL', 'News', 'Industry Calendar', 'Home Furnishings & Fixtures', 'Sporting Goods']
Run Code Online (Sandbox Code Playgroud)

显然,我可以切出每个列表中的第一项来获取我需要的数据.

我不明白的是,当我添加tbody/到start(//tbody/tr[#]/td/a/text())时,它再次失败,即使Chrome中的控制台清楚地显示两个trs都是tbody元素的子元素.

Chrome控制台显示HTML层次结构

为什么会这样?

Mar*_*ers 5

浏览器解析HTML并从中构建元素树; 在该过程中,他们将插入输入HTML文档中可能缺少的元素.

在这种情况下,<tbody>元素不在源HTML中.您的浏览器会插入它们,因为它们隐藏在结构中(如果缺少).但是,LXML不会插入它们.

由于这个原因,您的浏览器工具不是构建XPath查询的最佳工具.

删除tbody/路径元素会产生您要查找的结果:

>>> sect_p = '//*[@id="yfncsumtab"]/tr[2]/td[1]/table[2]/tr/td/table/tr[1]/td/a/text()'
>>> indu_p = '//*[@id="yfncsumtab"]/tr[2]/td[1]/table[2]/tr/td/table/tr[2]/td/a/text()'
>>> tree.xpath(sect_p)
['Consumer Goods']
>>> tree.xpath(indu_p)
['Electronic Equipment']
Run Code Online (Sandbox Code Playgroud)