在Scrapy中去除 \n、\t、\r

22

我正在尝试使用Scrapy爬虫去除\r \n \t字符,然后生成一个json文件。

我有一个“description”对象,它充满了换行符,并且它不能实现我想要的功能:将每个描述与标题匹配。

我尝试使用map(unicode.strip()),但它并不能真正起作用。由于我是Scrapy的新手,我不知道是否有另一种更简单的方法或map unicode的工作原理。

这是我的代码:

def parse(self, response):
    for sel in response.xpath('//div[@class="d-grid-main"]'):
        item = xItem()
        item['TITLE'] = sel.xpath('xpath').extract()
        item['DESCRIPTION'] = map(unicode.strip, sel.xpath('//p[@class="class-name"]/text()').extract())

我也尝试了以下方法:

item['DESCRIPTION'] = str(sel.xpath('//p[@class="class-name"]/text()').extract()).strip()

但是它报错了,最好的解决方法是什么?


你好,"it doesn't really work" 是什么意思?strip() 只考虑字符串的开头和结尾字符,所以如果你想去掉字符串中间的任何内容,你需要使用其他方法。如果这是你的问题,那么 import rere.sub('[\r\n\t]', '', 'Hel\nlo\r!') 可以帮助你。 - Quentin Pradet
我建议查看 ItemLoaders http://doc.scrapy.org/en/latest/topics/loaders.html ,它可以让你管理你的 Item 的输入和输出。 - Granitosaurus
QuentinPradet谢谢,事实上Paul的回答很好,我不知道那个。Granitosaurus我会学习的,谢谢。 - Lara M.
8个回答

23

unicode.strip只处理字符串开头和结尾的空格字符。

返回去除了前导和尾随字符的字符串的副本。

不会处理中间的\n, \r, 或者 \t

您可以使用自定义方法来删除字符串内部的这些字符(使用正则表达式模块),甚至可以使用XPath的normalize-space()

通过剥离前导和尾随空格并将一系列空格字符替换为单个空格,返回参数字符串的空格规范化版本。

Python shell会话示例:

>>> text='''<html>
... <body>
... <div class="d-grid-main">
... <p class="class-name">
... 
...  This is some text,
...  with some newlines \r
...  and some \t tabs \t too;
... 
... <a href="http://example.com"> and a link too
...  </a>
... 
... I think we're done here
... 
... </p>
... </div>
... </body>
... </html>'''
>>> response = scrapy.Selector(text=text)
>>> response.xpath('//div[@class="d-grid-main"]')
[<Selector xpath='//div[@class="d-grid-main"]' data=u'<div class="d-grid-main">\n<p class="clas'>]
>>> div = response.xpath('//div[@class="d-grid-main"]')[0]
>>> 
>>> # you'll want to use relative XPath expressions, starting with "./"
>>> div.xpath('.//p[@class="class-name"]/text()').extract()
[u'\n\n This is some text,\n with some newlines \r\n and some \t tabs \t too;\n\n',
 u"\n\nI think we're done here\n\n"]
>>> 
>>> # only leading and trailing whitespace is removed by strip()
>>> map(unicode.strip, div.xpath('.//p[@class="class-name"]/text()').extract())
[u'This is some text,\n with some newlines \r\n and some \t tabs \t too;', u"I think we're done here"]
>>> 
>>> # normalize-space() will get you a single string on the whole element
>>> div.xpath('normalize-space(.//p[@class="class-name"])').extract()
[u"This is some text, with some newlines and some tabs too; and a link too I think we're done here"]
>>> 

我想要对整个body进行normalize-space操作: response.xpath('.').extract() 这个方法可以实现,但是使用normalize-space: response.xpath('normalize-space(.)').extract() 会导致像<html>这样的HTML标签被移除,为什么? - user7367392
1
@Baks,normalize-space(。) 返回上下文节点的空格规范化字符串值,它是后代文本节点的连接:_"元素节点的字符串值是元素节点中所有文本节点后代的字符串值按文档顺序连接而成。"_ - paul trmbrth

7

我是一个 Python、Scrapy 的新手,今天遇到了类似的问题。在以下模块/函数 w3lib.html.replace_escape_chars 的帮助下解决了这个问题。我为我的物品加载器创建了一个默认输入处理器,它可以正常工作,你也可以将其绑定到特定的 Scrapy.Field() 上,并且它可以与 css 选择器和 csv feed exports 一起使用。

from w3lib.html import replace_escape_chars
yourloader.default_input_processor = MapCompose(relace_escape_chars)

3

正如Paul Trmbrth在他的回答中建议的那样,

这里涉及到IT技术相关内容。
div.xpath('normalize-space(.//p[@class="class-name"])').extract()

这可能是您想要的。然而,normalize-space函数也会将字符串中包含的空格压缩为一个空格。如果您只想删除\r\n\t而不干扰其他空格,则可以使用translate()函数来移除字符。

trans_table = {ord(c): None for c in u'\r\n\t'}
item['DESCRIPTION] = ' '.join(s.translate(trans_table) for s in sel.xpath('//p[@class="class-name"]/text()').extract())

这仍会留下前导和尾随的空格,而这些空格不在集合\r\n\t中。如果您还想摆脱它们,请插入调用strip()的语句:
item['DESCRIPTION] = ' '.join(s.strip().translate(trans_table) for s in sel.xpath('//p[@class="class-name"]/text()').extract())

太好了。我以前不知道这个,它解决了我所有的空格问题,而无需使用正则表达式。 - Echelon
这段代码对我有用,谢谢。 div.xpath('normalize-space(.//p[@class="class-name"])').extract() - Janib Soomro

1
从alibris.com提取价格的最简单的示例是:
response.xpath('normalize-space(//td[@class="price"]//p)').get()

0
你可以尝试使用css和get().strip()的组合,这对我很有效。

1
您的回答可以通过添加更多支持性信息来改善。请编辑以添加更多细节,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0
str(i.css("p::text")[1].extract()).strip()

0
当我使用scrapy爬取网页时,我遇到了同样的问题。我有两种方法来解决这个问题。第一种方法是使用replace()函数。因为"response.xpath"返回一个列表格式,而replace函数只能操作字符串格式。所以我使用for循环将列表中的每个项目作为字符串提取出来,替换其中的'\n'和'\t',然后将其添加到一个新列表中。
import re
test_string =["\n\t\t", "\n\t\t\n\t\t\n\t\t\t\t\t", "\n", "\n", "\n", "\n", "Do you like shopping?", "\n", "Yes, I\u2019m a shopaholic.", "\n", "What do you usually shop for?", "\n", "I usually shop for clothes. I\u2019m a big fashion fan.", "\n", "Where do you go shopping?", "\n", "At some fashion boutiques in my neighborhood.", "\n", "Are there many shops in your neighborhood?", "\n", "Yes. My area is the city center, so I have many choices of where to shop.", "\n", "Do you spend much money on shopping?", "\n", "Yes and I\u2019m usually broke at the end of the month.", "\n", "\n\n\n", "\n", "\t\t\t\t", "\n\t\t\t\n\t\t\t", "\n\n\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t"]
print(test_string)
        # remove \t \n    
a = re.compile(r'(\t)+')     
b = re.compile(r'(\n)+')
text = []
for n in test_string:
    n = a.sub('',n)
    n = b.sub('',n)
    text.append(n)
print(text)
        # remove all ''
while '' in text:
    text.remove('')
print(text)

第二种方法使用map()和strip。map()函数直接处理列表并获取原始格式。'Unicode'在Python2中使用,而在Python3中更改为'str',如下所示:
text = list(map(str.strip, test_string))
print(text)

strip函数仅从字符串的开头和结尾删除\n\t\r,而不是字符串中间。它与remove函数不同。

0

如果你想保留列表而不是所有连接的字符串,就无需添加额外步骤,你只需要简单地调用getall()而不是get()

response.xpath('normalize-space(.//td[@class="price"]/text())').getall()

另外,你应该在最后加上text()

希望它能帮助任何人!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接