使用Scrapy解析时如何保留换行符

5 投票
2 回答
4800 浏览
提问于 2025-04-17 09:37

我写了一个Scrapy爬虫,用来从网页上提取文本。这个爬虫在很多页面上都能正确解析和输出内容,但在一些页面上却出现了问题。我想在文档中保持换行和格式。像这个页面 http://www.state.gov/r/pa/prs/dpb/2011/04/160298.htm 的格式是这样的:

2011年4月7日

马克·C·托纳

下午2:03 EDT

托纳先生:大家下午好。首先有几件事要说,然后我会回答你们的问题。我们强烈谴责对以色列南部无辜平民的攻击,以及来自加沙的持续火箭袭击。正如我们多次重申的,没有任何理由可以为针对无辜平民的行为辩护,应该追究那些实施这些恐怖行为的责任。我们特别关注报告中提到的使用先进反坦克武器攻击平民的情况,并重申所有国家都有责任根据相关的联合国安理会决议,防止非法武器和弹药的交易。还有一句简短的声明——

提问:我们能在这个问题上停留一秒钟吗?

托纳先生:好的,马特,请说。

提问:显然,目标是一个校车。这让你更加愤怒吗?

托纳先生:任何针对无辜平民的攻击都是令人厌恶的,但这种攻击的性质尤其如此。

而像这个页面 http://www.state.gov/r/pa/prs/dpb/2009/04/121223.htm 的输出却没有换行,内容是这样的:

2009年4月2日

罗伯特·伍德

上午11:53 EDT托纳先生:大家早上好。我想现在还是早上。欢迎参加简报。我没有什么要说的,所以——先生。提问:北朝鲜已经将加油船等移动到现场附近。他们可能在为这枚导弹加油,也可能没有。你对北朝鲜此刻有什么高见?伍德先生:嗯,马特,我不打算评论情报问题。但我再说一遍,我们呼吁北朝鲜停止发射任何类型的导弹。这是适得其反的,具有挑衅性,会进一步加剧该地区的紧张局势。我们希望北朝鲜能回到六方会谈框架内,专注于无核化。是的。提问:日本也表示,如果这次发射继续,他们将呼吁召开安理会紧急会议。这也是你们希望的事情吗?伍德先生:嗯,让我们看看这个测试是否会发生。我们当然希望它不会。再次呼吁北朝鲜不要这样做。但如果这个测试真的进行,我们会和我们的盟友进行讨论。

我使用的代码如下:

def parse_item(self, response):
    self.log('Hi, this is an item page! %s' % response.url) 

    hxs = HtmlXPathSelector(response)

    speaker = hxs.select("//span[contains(@class, 'official_s_name')]") #gets the speaker
    speaker = speaker.select('string()').extract()[0] #extracts speaker text
    date = hxs.select('//*[@id="date_long"]') #gets the date
    date = date.select('string()').extract()[0] #extracts the date
    content = hxs.select('//*[@id="centerblock"]') #gets the content
    content = content.select('string()').extract()[0] #extracts the content

    texts = "%s\n\n%s\n\n%s" % (date, speaker, content) #puts everything together in a string

    filename = ("/path/StateDailyBriefing-" + '%s' ".txt") % (date) #creates a file using the date

    #opens the file defined above and writes 'texts' using utf-8
    with codecs.open(filename, 'w', encoding='utf-8') as output:
        output.write(texts)

我认为问题出在页面的HTML格式上。在那些输出文本不正确的页面中,段落是通过 <br> <p></p> 来分隔的,而在那些输出正确的页面中,段落是包含在 <p align="left" dir="ltr"> 中的。所以,虽然我已经找到了这个问题,但我不确定如何让所有内容都以正确的格式一致输出。

2 个回答

3

试试这个 xpath:

//*[@id="centerblock"]//text()
6

问题是,当你使用 text()string() 时,<br> 标签不会被转换成换行符。

解决方法是,在进行 XPath 请求之前,先把 <br> 标签替换掉。代码如下:

response = response.replace(body=response.body.replace('<br />', '\n')) 
hxs = HtmlXPathSelector(response)

另外,如果你知道只有一个节点,可以用 text() 来代替 string()

date = hxs.select('//*[@id="date_long"]/text()').extract()[0]

撰写回答