带有Xpath / BeautifulSoup的h3 / h2标签之间的HTML

时间:2015-08-03 04:00:17

标签: python html xpath beautifulsoup scrapy

我使用Scrapy作为项目,我得到以下html:

<h3><span class="my_class">First title</span></h3>
<ul>
    <li>Text for the first title... li #1</li>
</ul>
<ul>
    <li>Text for the first title... li #2</li>
</ul>
<h3><span class="my_class">Second title</span></h3>
<ul>
    <li>Text for the second title... li #1</li>
</ul>
<ul>
    <li>Text for the second title... li #2</li>
</ul>

现在,当我使用response.xpath(".//ul/li/text()").extract()它确实有用时,它会给我["Text for the first title... li #1", "Text for the first title... li #2", "Text for the second title... li #1", "Text for the second title... li #2"]但这部分是我想要的。

我想要两个列表,一个用于First title,另一个用于Second title。 这样结果将是:

first_title = ["Text for the first title... li #1", "Text for the first title... li #2"]
second_title = ["Text for the second title... li #1", "Text for the second title... li #2"]

我仍然不知道如何实现这一目标。我目前正在使用Scrapy来获取HTML;使用xpathPython的解决方案对我来说非常理想。但不知何故,我相信BeautifulSoup对这类任务有用。

您对如何在Python中执行此操作有任何想法吗?

3 个答案:

答案 0 :(得分:1)

使用Beautiful Soup进行此操作的方法如下。 (我已经将结果存储在一个字典而不是单独命名的列表中,以防你事先不知道你有多少。)

from bs4 import BeautifulSoup

soup = BeautifulSoup(url)
groups = soup.find_all('ul')
results = {}
for group in groups:
   results[group.find_previous_sibling().text] = [e.text for e in a.find_all('li')]

答案 1 :(得分:1)

如果您想使用BeautifulSoup,可以使用findNext方法:

h3s = soup.find_all("h3")
for h3 in h3s:
    print h3.text
    print h3.findNext("ul").text

在这种情况下,BS更容易使用,因为它可以更容易地找到元素的兄弟。

使用简单的XPath,您可以执行以下操作:

h3s = data.xpath('//h3')
for h3 in h3s:
    print h3.xpath('.//text()')
    h3.xpath('./following-sibling::ul')[0].xpath('.//text()')

这是针对上面的示例修复的。如果您需要一些通用的方法,我会说BS是正确的工具,因为可用的方法。

答案 2 :(得分:1)

您可以在Scrapy中使用XPath和CSS选择器。

这是一个示例解决方案(在ipython会话中;我只将第二个块中的#1和#2更改为#3,#4更改为更明显):

element_answer = elements[new Random().nextInt(elements.length)];

在OP的评论问题之后编辑:

  

每个In [1]: import scrapy In [2]: selector = scrapy.Selector(text="""<h3><span class="my_class">First title</span></h3> ...: <ul> ...: <li>Text for the first title... li #1</li> ...: <li>Text for the first title... li #2</li> ...: </ul> ...: <h3><span class="my_class">Second title</span></h3> ...: <ul> ...: <li>Text for the second title... li #3</li> ...: <li>Text for the second title... li #4</li> ...: </ul>""") In [3]: for title_list in selector.css('h3 + ul'): ...: print title_list.xpath('./li/text()').extract() ...: [u'Text for the first title... li #1', u'Text for the first title... li #2'] [u'Text for the second title... li #3', u'Text for the second title... li #4'] In [4]: for title_list in selector.css('h3 + ul'): print title_list.css('li::text').extract() ...: [u'Text for the first title... li #1', u'Text for the first title... li #2'] [u'Text for the second title... li #3', u'Text for the second title... li #4'] In [5]: 标记都包含在自己的<li>中(...)是否有任何方法可以扩展它以使其查找{{1下方的所有<ul>标记标签?

如果ulh3都是兄弟姐妹,那么选择下一个h3之前的ul的一种方法是计算preceding h3 siblings

考虑此输入HTML代码段:

ul

第一个h3行有1个<h3><span class="my_class">First title</span></h3> <ul><li>Text for the first title... li #1</li></ul> <ul><li>Text for the first title... li #2</li></ul> <h3><span class="my_class">Second title</span></h3> <ul><li>Text for the second title... li #3</li></ul> <ul><li>Text for the second title... li #4</li></ul> 个兄弟,第3个<ul><li>行有2个h3个兄弟姐妹。

因此,对于每个<ul><li>,您需要关注h3兄弟姐妹,这些兄弟姐妹到目前为止已经看到了h3的确切数量。

首先:

ul

然后,

h3

等等。

following-sibling::ul[count(preceding-sibling::h3)=1] following-sibling::ul[count(preceding-sibling::h3)=2]选择的enumerate()的帮助下,这个想法在行动中(请记住XPath positions start at 1,而不是0):

h3