1

我试图实现一个lxml, xpath代码来解析来自链接的 html:https://www.theice.com/productguide/ProductSpec.shtml?specId=251 具体来说,我试图解析<tr class="last">页面末尾附近的表格。

我想获取该子表中的文本,例如:“纽约”和旁边列出的时间(伦敦和新加坡也一样)。

我有以下代码(不能正常工作):

doc = lxml.html.fromstring(page)
tds = doc.xpath('//table[@class="last"]//table[@id"tradingHours"]/tbody/tr/td/text()')

使用 BeautifulSoup:

table = soup.find('table', attrs={'id':'tradingHours'})
for td in table.findChildren('td'):
    print td.text

实现这一目标的最佳方法是什么?我想用lxmlnot beautifulSoup(只是为了看看区别)。

4

3 回答 3

3

您的lxml代码非常接近工作。主要问题是table标签不是具有class="last"属性的标签。相反,它是一个tr具有该属性的标签:

    </tr><tr class="last"><td>TRADING HOURS</td>&#13;

因此,

//table[@class="last"]

没有匹配项。还有一个小的语法错误:@id"tradingHours"应该是@id="tradingHours".

您也可以//table[@class="last"]完全省略,因为table[@id="tradingHours"]足够具体。


与您的 BeautifulSoup 代码最接近的模拟是:

import urllib2
import lxml.html as LH

url = 'https://www.theice.com/productguide/ProductSpec.shtml?specId=251'
doc = LH.parse(urllib2.urlopen(url))
for td in doc.xpath('//table[@id="tradingHours"]//td/text()'):
    print(td.strip())

grouper recipe , zip(*[iterable]*n), 在解析表时通常非常有用。它将项目收集到项目iterable组中n。我们可以像这样在这里使用它:

texts = iter(doc.xpath('//table[@id="tradingHours"]//td/text()'))
for group in zip(*[texts]*5):
    row = [item.strip() for item in group]
    print('\n'.join(row))
    print('-'*80)

我不太擅长解释石斑鱼食谱的工作原理,但我在这里做了一个尝试


此页面正在使用 JavaScript 重新格式化日期。要在 JavaScript 更改内容抓取页面,可以使用selenium

import urllib2
import lxml.html as LH
import contextlib
import selenium.webdriver as webdriver

url = 'https://www.theice.com/productguide/ProductSpec.shtml?specId=251'
with contextlib.closing(webdriver.PhantomJS('phantomjs')) as driver:
    driver.get(url)
    content = driver.page_source
    doc = LH.fromstring(content)
    texts = iter(doc.xpath('//table[@id="tradingHours"]//td/text()'))
    for group in zip(*[texts]*5):
        row = [item.strip() for item in group]
        print('\n'.join(row))
        print('-'*80)

产量

NEW YORK
8:00 PM-2:15 PM *
20:00-14:15
7:30 PM
19:30
--------------------------------------------------------------------------------
LONDON
1:00 AM-7:15 PM
01:00-19:15
12:30 AM
00:30
--------------------------------------------------------------------------------
SINGAPORE
8:00 AM-2:15 AM *
08:00-02:15
7:30 AM
07:30
--------------------------------------------------------------------------------

请注意,在这种特殊情况下,如果您不想使用 selenium,则可以使用pytz自己解析和转换时间:

import dateutil.parser as parser
import pytz

text = 'Tue Jul 30 20:00:00 EDT 2013'
date = parser.parse(text)
date = date.replace(tzinfo=None)
print(date.strftime('%I:%M %p'))
# 08:00 PM

ny = pytz.timezone('America/New_York')
london = pytz.timezone('Europe/London')
london_date = ny.localize(date).astimezone(london)
print(london_date.strftime('%I:%M %p'))
# 01:00 AM
于 2013-07-31T02:11:54.347 回答
1

如果站点是正确的 html,则 id 属性是唯一的,您可以在doc.get_element_by_id('tradingHours').

import urllib
from lxml import html

url = 'https://www.theice.com/productguide/ProductSpec.shtml?specId=251'

response = urllib.urlopen(url).read()

h = html.document_fromstring(response)

print "BY ID"
tradingHours = h.get_element_by_id('tradingHours')

for tr in tradingHours.xpath('tbody/tr'):
    tds = tr.xpath('td')
    print tds[0].text.strip()
    for td in tds[1:]:
        print ' ', td.text.strip()

结果是

BY ID
NEW YORK
  Tue Jul 30 20:00:00 EDT 2013-Tue Jul 30 14:15:00 EDT 2013 *
  Tue Jul 30 19:30:00 EDT 2013
LONDON
  Tue Jul 30 20:00:00 EDT 2013-Tue Jul 30 14:15:00 EDT 2013
  Tue Jul 30 19:30:00 EDT 2013
SINGAPORE
  Tue Jul 30 20:00:00 EDT 2013-Tue Jul 30 14:15:00 EDT 2013 *
  Tue Jul 30 19:30:00 EDT 2013
于 2013-07-30T19:02:13.123 回答
1

我喜欢 css 选择器比 xpaths 更适应页面更改:

import urllib
from lxml import html

url = 'https://www.theice.com/productguide/ProductSpec.shtml?specId=251'

response = urllib.urlopen(url).read()

h = html.document_fromstring(response)
for tr in h.cssselect('#tradingHours tbody tr'):
    td = tr.cssselect('td')
    print td[0].text_content(), td[1].text_content()
于 2013-07-30T17:57:32.137 回答