使用 lxml 抓取动态 html 字段

Scraping dynamic html fields with lxml

我一直在尝试使用 lxml 抓取 HTML 页面的动态字段 代码非常简单,如下所示:

from lxml import html
import requests
page = requests.get('http://www.airmilescalculator.com/distance/blr-to-cdg/')
tree = html.fromstring(page.content)
miles = tree.xpath('//input[@class="distanceinput2"]/text()')
print miles

我导出的结果只是一个空列表[] 结果预计是列表中的一个数字。 但是我能够抓取同一页面的静态字段。

在此先感谢您的帮助。

您不能 select 来自 input 字段的文本节点,因为没有文本节点。

<input type="text" class="distanceinput2" .. />

要从 input 字段中获取 value,请使用:

miles = [node.value for node in tree.xpath('//input[@class="distanceinput2"]')]

你应该得到它们。

所需的值已计算出来,因此我们需要访问该页面并模拟一个 Click 来获取它们。splinter 包就是为此而制作的。

from pyvirtualdisplay import Display
display = Display(visible=0)
display.start()

from splinter import Browser

url = 'http://www.airmilescalculator.com/distance/blr-to-cdg/'

browser = Browser()
browser.visit(url)
browser.find_by_id('haemulti')[0].click()

print browser.find_by_id('totaldistancemiles')[0].value
print browser.find_by_id('totaldistancekm')[0].value
print browser.find_by_id('nauticalmiles')[0].value

browser.quit()


display.stop()

pyvirtualdisplay用于隐藏浏览器。

输出:

$python test.py 
4868
7834
4230

这里的问题是文本框中的值是由 javascript 添加的。当页面加载时,文本字段中的值为 0。因此,即使您抓取,您也不会获得该值,因为抓取的内容会得到这个

<input class="distanceinput2" id="totaldistancemiles" name="totaldistancemiles" readonly="readonly" size="5" title="Distance in miles" type="text" value="0"/>
<input class="distanceinput2" id="totaldistancekm" name="totaldistancekm" readonly="readonly" size="5" title="Distance in kilometers" type="text" value="0"/>
<input class="distanceinput2" id="nauticalmiles" name="nauticalmiles" readonly="readonly" size="5" title="Distance in nautical miles" type="text" value="0"/>

所以,如果你想得到网站上的价值,是不可能通过抓取的。

您可以试试 phantom JS,它就像一个无头浏览器。还没有试验过,但看起来有机会。这里有一个 link 可以提供帮助。

希望对您有所帮助!

如您所知,距离是根据对 Google 地图 API 的 XHR 调用结果动态计算的。 simulate/repeat 仅使用 requests 并不容易,因为您至少需要一个真实浏览器具有的 Javascript 引擎。

这里是你如何通过selenium and headless PhantomJS browser解决它:

from selenium import webdriver

driver = webdriver.PhantomJS()
driver.get("http://www.airmilescalculator.com/distance/blr-to-cdg/")

distance = driver.find_element_by_id("totaldistancemilestext").text
print(distance)

打印 4868.