使用scrapy将松散格式化的,原始的html消化成文本块

时间:2016-01-10 12:46:22

标签: python xpath scrapy

刚刚介绍给Scrapy。已经完成了基础教程,但觉得我不太了解如何使用它。

我需要解析的简单案例就像:

BASIC CASE
<li>
    <b>Descriptive Title</b>
    <br>
    The_first_paragraph_of_text
    <p>Second paragraphs of text</p>
    ...
    <p>Nth Paragraph of text</p>
</li>

我想要做的是生成一个包含两列的数据库记录,&#34; title&#34;和&#34; body_text&#34;。标题来自“描述性标题”&#39;而body_text来自于获取所有文本段落并连接成一个文本块。

我写了一些像

这样简单的东西
"""pulls out the Descriptive Title and all the <p>-wrapped paragraphs but misses the first paragraph (which isn't wrapped in a <p>"""
for sel in response.xpath("//li"):
    b = sel.xpath('b').extract()
    print "b = {0}\n".format(b)    
    for p in sel.xpath('p'):
        paragraph = p.xpath('text()').extract()
        print"\n{0}".format(paragraph)

但这并没有抓住第一段,只有第二段及以后的段落。而且,它对<li> html块的变体不稳健。

在一个变体中,第一段有时用斜体字包裹。

ITALICS COMPLICATION
<li>
    <b>Descriptive Title</b>
    <br>
    <i>Occasionally The_first_paragraph_of_text is in italics</i>
    <p>Second paragraphs of text</p>
    ...
    <p>Nth Paragraph of text</p>
</li>

在另一个变体中,有时<li>嵌入在某些段落块中。

SUB LIST-ITEM COMPLICATION
<li>
    <b>Descriptive Title</b>
    <br>
    <i>Occasionally The_first_paragraph_of_text is in italics</i>
    <p>Second paragraphs of text</p>
    <p>Sometimes paragraphs will have lists inside them
        <li>idea 1</li>
        <li>idea 2</li>
        <li>idea N</li>
    </p>
    <p>Nth Paragraph of text</p>
</li>

我怀疑我并没有在&#34; scrapythonic&#34;中消化html文件。办法。什么是正确的方法来编写更强大的选择器来提取我想要的东西?

1 个答案:

答案 0 :(得分:1)

更多的xpath问题而不是scrapy问题 如果您的标题始终位于第一个元素中,则为<b>标记 它很容易sel.xpath('b[1]/text()')

如果我是你,我会添加一些严格的断言 使它失败而不是废弃错误的标题文本 因为<b>标记通常可以扮演其他角色 尝试:
title, = sel.xpath('*[1][self::b and count(node())=count(text())]')
title = u'\n'.join(sel.xpath('text()'))
其内容如下(括号中的断言):
必须存在一个且只有一个标签(由title, =声明)
这是第一个标签(由[1]声明)
并且是<b>(由self::b声明) 并且只有文本节点(由count(text())=count(node())声明)

对于正文, 你将不得不习惯使用html进行格式化 除非你正在抓一个网站 它非常简单地格式化其主要内容 (例如安排了<p>标签)。

您可以按文档顺序获取所有文本后代: sel.xpath('.//text()')
但是,<script><style>标记可能会显示不需要的文字; 你不希望你的正文用javascript / css乱码填充 您可以通过以下方式阻止它们被选中:
sel.xpath('.//text()[not(parent::script or parent::style)]')
然后,您可能希望将提取的文本与u'\n'.join()

一起加入

这将解决您的问题,但不会处理所有不需要的标签 玩lxml.html.clean.Cleaner(style=True)左右 (记录在此http://lxml.de/lxmlhtml.html#cleaning-up-html
并考虑找一个将html呈现为文本的库。