web-dev-qa-db-fra.com

Bande \ n \ t \ r en tremblante

J'essaie de supprimer les caractères\r\n\t avec une araignée grinçante, créant ensuite un fichier json.

J'ai un objet "description" qui est plein de nouvelles lignes, et il ne fait pas ce que je veux: faire correspondre chaque description à un titre.

J'ai essayé avec map (unicode.strip ()) mais cela ne fonctionne pas vraiment. Étant nouveau dans le scrap, je ne sais pas s'il existe un autre moyen plus simple ni comment fonctionne la carte unicode.

Voici mon code:

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())

J'ai aussi essayé avec:

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

Mais cela a soulevé une erreur. Quelle est la meilleure façon?

19
Lara M.

unicode.strip ne traite que les caractères d'espacement au début et à la fin des chaînes

Renvoie une copie de la chaîne avec les caractères de début et de fin supprimés.

pas avec \n, \r ou \t au milieu.

Vous pouvez soit utiliser une méthode personnalisée pour supprimer ces caractères dans la chaîne (à l'aide du module d'expression régulière), soit même utiliser XPath's normalize-space()

retourne la chaîne d'argument avec des espaces normalisés en supprimant les espaces de début et de fin et en remplaçant les séquences de caractères d'espaces par un seul espace .

Exemple python Session 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"]
>>> 
20
paul trmbrth

Je suis un débutant en python et grincheux, j'ai eu un problème similaire aujourd'hui, j'ai résolu cela à l'aide du module/fonction suivant w3lib.html.replace_escape_chars J'ai créé un processeur d'entrée par défaut pour mon chargeur d'objets et cela fonctionne sans aucun problème, vous pouvez également le lier sur le scrapy.Field () spécifique, et la bonne chose qu'il fonctionne avec les sélecteurs css et les exportations de flux csv:

from w3lib.html import replace_escape_chars
yourloader.default_input_processor = MapCompose(relace_escape_chars)
5
Peter Húbek

Comme le suggère Paul Trmbrth dans sa réponse ,

div.xpath('normalize-space(.//p[@class="class-name"])').extract()

est susceptible d'être ce que vous voulez. Cependant, normalize-space condense également les espaces contenus dans la chaîne en un seul espace. Si vous souhaitez uniquement supprimer \r, \n Et \t Sans déranger les autres espaces, vous pouvez utiliser translate() pour supprimer des caractères.

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())

Cela laissera toujours des espaces de début et de fin qui ne sont pas dans l'ensemble \r, \n Ou \t. Si vous voulez également vous en débarrasser, insérez simplement un appel à strip():

item['DESCRIPTION] = ' '.join(s.strip().translate(trans_table) for s in sel.xpath('//p[@class="class-name"]/text()').extract())
3
mhawke

Lorsque j'utilise scrapy pour explorer une page Web, je rencontre le même problème. J'ai deux façons de résoudre ce problème. Utilisez d'abord la fonction replace (). AS "response.xpath" renvoie un format de liste mais la fonction de remplacement ne fonctionne que sous forme de chaîne. Je récupère donc chaque élément de la liste sous forme de chaîne en utilisant une boucle for, remplacez '\ n' '\ t' dans chaque élément, puis ajouter à une nouvelle liste.

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)

La deuxième méthode utilise map () et strip. La fonction map () traite directement la liste et obtient le format d'origine. "Unicode" est utilisé en python2 et changé en "str" ​​en python3, comme suit:

text = list(map(str.strip, test_string))
print(text)

La fonction strip ne supprime que le\n\t\r du début et de la fin de la chaîne, pas le milieu de la chaîne.C'est différent de la fonction remove.

0
Ryan

L'exemple le plus simple pour extraire le prix de alibris.com est

response.xpath('normalize-space(//td[@class="price"]//p)').get()
0
user1994