BeautifulSoup Python抓取中的嵌套标签/表

时间:2014-02-20 20:48:28

标签: python web-scraping beautifulsoup

我在谷歌上花了半天时间寻找合适的答案。我最接近的是StackOverflow帖子:Nested tags in BeautifulSoup - Python

有效地,我使用Python中的BeautifulSoup从具有嵌套元素的复杂页面中抓取等待时间数据。一些HTML元素有类/ ID,但大多数没有。看看DOM,我可以看到我想要的元素的路径。我已经编写了一个指向正确路径的初步脚本(......我认为)但是控制台不断打印出一个空数组。即使更改此代码以打印出简单的内容(如soup.select(' body h2'))也不会打印任何内容。这是我的代码

from BeautifulSoup import BeautifulSoup
import requests

url = 'http://www.alexianbrothershealth.org/wait-times'
r = requests.get(url)

soup = BeautifulSoup(r.text)
wait_times = soup.select('body div div div div div div div table tbody tr td')

print wait_times

我需要改变什么才能使这项工作成功?我有更多的网站可以访问,所以找出.select()指针的正确语法真的会有所帮助。我尝试过使用带有XPath的lxml,并打印出一个空数组。页面来源告诉我它在HTML中并且没有通过客户端上的javascript加载所以我应该没关系。

PS我是个新手,所以任何复杂的答案都会完全丢失在我身上;)

2 个答案:

答案 0 :(得分:0)

我认为select不是您正在寻找的BeautifulSoup方法。选择使用css选择器,但您只是在寻找正确的标签集。

如果您所寻找的所有时间都在,我会使用

tds = soup.find_all("td")
for cell in tds:
    children = cell.findChildren()
    ... do actual work ...

或者,如果你想使用select(你绝对可以),请尝试删除整个第一组标签:

soup.select("table tbody tr td")

工作正常。

答案 1 :(得分:0)

我知道这是一个老问题,但我最近一直在和BeautifulSoup合作,并且认为我提供了一个解决方案。希望我在代码中的评论将为每个部分提供充分的解释。

# instead of parsing the entire html doc, only parse the division that
# contains ER and IC wait times
soup = BeautifulSoup(req.text, 'lxml', parse_only=SoupStrainer(id='PageContent'))

让我补充一点,许多网页抓取工作只涉及提取一小部分html / xml响应。 SoupStrainer类提供了一种减少soup对象大小和浏览html / xml文档相关部分的绝佳方法。

waittimes = []

急诊室等待时间包含在html <table>中。表中的每个<td>标记都包含一个设施的一行信息。

# isolate the ER wait times in the only <table> in the soup object
ERtimes = soup('table')
# further isolate the data by filtering on the <td> tags
tds = ERtimes[0]('td')

# in this case every other <td> tag contains data. the others contain
# formatting instructions
for td in tds[::2]:
# extract only the text data in the <td> tag using stripped_strings generator
# keep only the facility name, wait time and the timestamp
waittimes.append([str for i, str in enumerate(td.stripped_strings) if i in [0, 2, 3]])

所有8个设施的即时护理等待时间包含在一个<div>标签中。因此,解析的处理方式与ER时间不同。

# isolate the IC wait times which are contained in a <div> tag
# find all of the <div> tags but keep the last one which has the data
# for all 8 facilities
ICtimes = soup('div')[-1] 

# once again use the stripped_strings generator to extract the pertinent text data
# however, in this case the data from the 8 facilities are returned into a single list
longlist = [str for str in ICtimes.stripped_strings]
# list comprehension to return the data from the single list into groups of 3
# which are facility name, wait time and timestamp
waittimes.extend([longlist[i:i+3] for i in xrange(0, len(longlist), 3)])

以下是等待时间:

In [162]: waittimes
Out[162]: 
[[u'Alexian Brothers Medical Center',u'0 minutes',u'as of 1/7/2016 10:38:37 AM'],
 [u'St. Alexius Medical Center',u'3 HOURS 40 MINS',u'as of 1/6/2016 6:51:11 PM'],
 [u'Addison', u'30 minutes', u'as of 1/7/2016 10:44:44 AM'],
 [u'Elk Grove', u'120 minutes', u'as of 1/7/2016 11:42:22 AM'],
 [u'Bensenville', u'45 mins', u'as of 1/7/2016 10:49:05 AM'],
 [u'Hanover Park', u'15 Mins', u'as of 1/7/2016 11:45:08 AM'],
 [u'Mt. Prospect', u'1 hour', u'as of 1/7/2016 11:22:53 AM'],
 [u'Schaumburg', u'1 hour', u'as of 1/7/2016 11:56:10 AM'],
 [u'Palatine', u'30 minutes', u'as of 1/7/2016 12:06:35 PM']]

当然,我没有编写清理数据所需的例程。我专注于提取相关数据并以结构化格式呈现。