2016-03-14 4 views
1

Хорошо, вот и проблема. Я начинающий, который только начал вникать в scrapy/python.Scrapy экспортирует странные символы в файл csv

Я использую следующий код, чтобы соскрести веб-сайт и сохранить результаты в формате csv. Когда я смотрю в командной строке, он превращает слова, подобные Officiële, в Offici \ xele. В файле csv он изменяет его на offici? Le. Я думаю, это связано с тем, что он сохраняет в unicode вместо UTF-8? У меня, однако, есть 0 подсказок, как изменить свой код, и я пробовал все утро до сих пор.

Может ли кто-нибудь помочь мне здесь? Я специально смотрю на то, чтобы убедиться, что элемент [publicatietype] работает правильно. Как его кодировать/декодировать? Что мне нужно написать? Я попытался использовать replace ('Ã «', 'ë'), но это дает мне ошибку (символ не ASCCI, но не объявленная кодировка).

class pagespider(Spider): 
    name = "OBSpider" 
    #max_page is put here to prevent endless loops; make it as large as you need. It will try and go up to that page 
    #even if there's nothing there. A number too high will just take way too much time and yield no results 
    max_pages = 1 

    def start_requests(self): 
     for i in range(self.max_pages): 
      yield scrapy.Request("https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=%d&sorttype=1&sortorder=4" % (i+1), callback = self.parse) 


    def parse(self, response): 
     for sel in response.xpath('//div[@class = "lijst"]/ul/li'): 
      item = ThingsToGather() 
      item["titel"] = ' '.join(sel.xpath('a/text()').extract()) 
      deeplink = ''.join(["https://zoek.officielebekendmakingen.nl/", ' '.join(sel.xpath('a/@href').extract())]) 
      request = scrapy.Request(deeplink, callback=self.get_page_info) 
      request.meta['item'] = item 
      yield request 

    def get_page_info(self, response): 
     for sel in response.xpath('//*[@id="Inhoud"]'): 
      item = response.meta['item'] 

    #it loads some general info from the header. If this string is less than 5 characters, the site probably is a faulthy link (i.e. an error 404). If this is the case, then it drops the item. Else it continues 

      if len(' '.join(sel.xpath('//div[contains(@class, "logo-nummer")]/div[contains(@class, "nummer")]/text()').extract())) < 5: 
       raise DropItem() 
      else: 
       item["filename"] = ' '.join(sel.xpath('//*[@id="downloadPdfHyperLink"]/@href').extract()) 
       item['publicatiedatum'] = sel.xpath('//span[contains(@property, "http://purl.org/dc/terms/available")]/text()').extract() 
       item["publicatietype"] = sel.xpath('//span[contains(@property, "http://purl.org/dc/terms/type")]/text()').extract() 
       item["filename"] = ' '.join(sel.xpath('//*[@id="downloadPdfHyperLink"]/@href').extract()) 
       item = self.__normalise_item(item, response.url) 

    #if the string is less than 5, then the required data is not on the page. It then needs to be 
    #retrieved from the technical information link. If it's the proper link (the else clause), you're done and it proceeds to 'else' 
       if len(item['publicatiedatum']) < 5: 
        tech_inf_link = ''.join(["https://zoek.officielebekendmakingen.nl/", ' '.join(sel.xpath('//*[@id="technischeInfoHyperlink"]/@href').extract())]) 
        request = scrapy.Request(tech_inf_link, callback=self.get_date_info) 
        request.meta['item'] = item 
        yield request 
       else: 
        yield item 

    def get_date_info (self, response): 
     for sel in response.xpath('//*[@id="Inhoud"]'): 
      item = response.meta['item'] 
      item["filename"] = sel.xpath('//span[contains(@property, "http://standaarden.overheid.nl/oep/meta/publicationName")]/text()').extract() 
      item['publicatiedatum'] = sel.xpath('//span[contains(@property, "http://purl.org/dc/terms/available")]/text()').extract() 
      item['publicatietype'] = sel.xpath('//span[contains(@property, "http://purl.org/dc/terms/type")]/text()').extract() 
      item["filename"] = ' '.join(sel.xpath('//*[@id="downloadPdfHyperLink"]/@href').extract()) 
      item = self.__normalise_item(item, response.url)  
      return item 

    # commands below are intended to clean up strings. Everything is sent to __normalise_item to clean unwanted characters (strip) and double spaces (split) 

    def __normalise_item(self, item, base_url): 
     for key, value in vars(item).values()[0].iteritems(): 
      item[key] = self.__normalise(item[key]) 

     item ['titel']= item['titel'].replace(';', '& ') 
     return item 

    def __normalise(self, value): 
     value = value if type(value) is not list else ' '.join(value) 
     value = value.strip() 
     value = " ".join(value.split()) 
     return value 

ОТВЕТ:

См комментарий Полем trmbrth ниже. Проблема не в скрипике, это превосходно.

Для всех, кто сталкивается с этим вопросом. Tldr: импортирует данные в excel (в меню данных на ленте) и переключает Windows (ANSI) или что-то еще, что он включен в Unicode (UTF-8).

ответ

0

Для кодирования строки вы можете напрямую использовать encode("utf-8"). Что-то вроде этого:

item['publicatiedatum'] = ''.join(sel.xpath('//span[contains(@property, "http://purl.org/dc/terms/available")]/text()').extract()).encode("utf-8") 
1

Officiële будет представлена ​​как u'Offici\xeble' в Python 2, как показано в примере питона оболочки сессии ниже (нет необходимости беспокоиться о \xXX персонажей, это просто, как Python представляет не-ASCII символы Unicode)

$ python 
Python 2.7.9 (default, Apr 2 2015, 15:33:21) 
[GCC 4.9.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> u'Officiële' 
u'Offici\xeble' 
>>> u'Offici\u00EBle' 
u'Offici\xeble' 
>>> 

Я думаю, это потому, что спасает в Юникода вместо UTF-8

UTF-8 - это кодировка, Юникод нет.

ë, a.k.a U+00EB, a.k.a LATIN SMALL LETTER E WITH DIAERESIS, будет UTF-8 кодируются как 2 байта, \xc3 и \xab

>>> u'Officiële'.encode('UTF-8') 
'Offici\xc3\xable' 
>>> 

В файле CSV, он меняет его на officià «ле.

Если вы видите это, вероятно, вам нужно установить входную кодировку в UTF-8 при открытии CSV-файла внутри вашей программы.

Экспортер Scrapy CSV будет писать строки Юникода Python как кодированные строки UTF-8 в выходном файле.

Scrapy селекторы будет выводить строки Unicode:

$ scrapy shell "https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4" 
2016-03-15 10:44:51 [scrapy] INFO: Scrapy 1.0.5 started (bot: scrapybot) 
(...) 
2016-03-15 10:44:52 [scrapy] DEBUG: Crawled (200) <GET https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4> (referer: None) 
(...) 
In [1]: response.css('div.menu-bmslink > ul > li > a::text').extract() 
Out[1]: 
[u'Offici\xeble bekendmakingen vandaag', 
u'Uitleg nieuwe nummering Handelingen vanaf 1 januari 2011', 
u'Uitleg nieuwe\r\n   nummering Staatscourant vanaf 1 juli 2009'] 

In [2]: for t in response.css('div.menu-bmslink > ul > li > a::text').extract(): 
    print t 
    ...:  
Officiële bekendmakingen vandaag 
Uitleg nieuwe nummering Handelingen vanaf 1 januari 2011 
Uitleg nieuwe 
      nummering Staatscourant vanaf 1 juli 2009 

Давайте посмотрим, что паук извлечения этих строк в графах приведет вас в CSV:

$ cat testspider.py 
import scrapy 


class TestSpider(scrapy.Spider): 
    name = 'testspider' 
    start_urls = ['https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4'] 

    def parse(self, response): 
     for t in response.css('div.menu-bmslink > ul > li > a::text').extract(): 
      yield {"link": t} 

Run паука и задать для вывода CSV:

$ scrapy runspider testspider.py -o test.csv 
2016-03-15 11:00:13 [scrapy] INFO: Scrapy 1.0.5 started (bot: scrapybot) 
2016-03-15 11:00:13 [scrapy] INFO: Optional features available: ssl, http11 
2016-03-15 11:00:13 [scrapy] INFO: Overridden settings: {'FEED_FORMAT': 'csv', 'FEED_URI': 'test.csv'} 
2016-03-15 11:00:14 [scrapy] INFO: Enabled extensions: CloseSpider, FeedExporter, TelnetConsole, LogStats, CoreStats, SpiderState 
2016-03-15 11:00:14 [scrapy] INFO: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats 
2016-03-15 11:00:14 [scrapy] INFO: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 
2016-03-15 11:00:14 [scrapy] INFO: Enabled item pipelines: 
2016-03-15 11:00:14 [scrapy] INFO: Spider opened 
2016-03-15 11:00:14 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 
2016-03-15 11:00:14 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023 
2016-03-15 11:00:14 [scrapy] DEBUG: Crawled (200) <GET https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4> (referer: None) 
2016-03-15 11:00:14 [scrapy] DEBUG: Scraped from <200 https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4> 
{'link': u'Offici\xeble bekendmakingen vandaag'} 
2016-03-15 11:00:14 [scrapy] DEBUG: Scraped from <200 https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4> 
{'link': u'Uitleg nieuwe nummering Handelingen vanaf 1 januari 2011'} 
2016-03-15 11:00:14 [scrapy] DEBUG: Scraped from <200 https://zoek.officielebekendmakingen.nl/zoeken/resultaat/?zkt=Uitgebreid&pst=Tractatenblad|Staatsblad|Staatscourant|BladGemeenschappelijkeRegeling|ParlementaireDocumenten&vrt=Cybersecurity&zkd=InDeGeheleText&dpr=Alle&sdt=general_informationPublicatie&ap=&pnr=18&rpp=10&_page=1&sorttype=1&sortorder=4> 
{'link': u'Uitleg nieuwe\r\n   nummering Staatscourant vanaf 1 juli 2009'} 
2016-03-15 11:00:14 [scrapy] INFO: Closing spider (finished) 
2016-03-15 11:00:14 [scrapy] INFO: Stored csv feed (3 items) in: test.csv 
2016-03-15 11:00:14 [scrapy] INFO: Dumping Scrapy stats: 
{'downloader/request_bytes': 488, 
'downloader/request_count': 1, 
'downloader/request_method_count/GET': 1, 
'downloader/response_bytes': 12018, 
'downloader/response_count': 1, 
'downloader/response_status_count/200': 1, 
'finish_reason': 'finished', 
'finish_time': datetime.datetime(2016, 3, 15, 10, 0, 14, 991735), 
'item_scraped_count': 3, 
'log_count/DEBUG': 5, 
'log_count/INFO': 8, 
'response_received_count': 1, 
'scheduler/dequeued': 1, 
'scheduler/dequeued/memory': 1, 
'scheduler/enqueued': 1, 
'scheduler/enqueued/memory': 1, 
'start_time': datetime.datetime(2016, 3, 15, 10, 0, 14, 59471)} 
2016-03-15 11:00:14 [scrapy] INFO: Spider closed (finished) 

Проверить содержимое CSV-файла:

$ cat test.csv 
link 
Officiële bekendmakingen vandaag 
Uitleg nieuwe nummering Handelingen vanaf 1 januari 2011 
"Uitleg nieuwe 
      nummering Staatscourant vanaf 1 juli 2009" 
$ hexdump -C test.csv 
00000000 6c 69 6e 6b 0d 0a 4f 66 66 69 63 69 c3 ab 6c 65 |link..Offici..le| 
00000010 20 62 65 6b 65 6e 64 6d 61 6b 69 6e 67 65 6e 20 | bekendmakingen | 
00000020 76 61 6e 64 61 61 67 0d 0a 55 69 74 6c 65 67 20 |vandaag..Uitleg | 
00000030 6e 69 65 75 77 65 20 6e 75 6d 6d 65 72 69 6e 67 |nieuwe nummering| 
00000040 20 48 61 6e 64 65 6c 69 6e 67 65 6e 20 76 61 6e | Handelingen van| 
00000050 61 66 20 31 20 6a 61 6e 75 61 72 69 20 32 30 31 |af 1 januari 201| 
00000060 31 0d 0a 22 55 69 74 6c 65 67 20 6e 69 65 75 77 |1.."Uitleg nieuw| 
00000070 65 0d 0a 20 20 20 20 20 20 20 20 20 20 20 20 6e |e..   n| 
00000080 75 6d 6d 65 72 69 6e 67 20 53 74 61 61 74 73 63 |ummering Staatsc| 
00000090 6f 75 72 61 6e 74 20 76 61 6e 61 66 20 31 20 6a |ourant vanaf 1 j| 
000000a0 75 6c 69 20 32 30 30 39 22 0d 0a     |uli 2009"..| 
000000ab 

Вы можете убедиться, что ë правильно кодируются как c3 ab

Я могу видеть данные файла правильно при использовании LibreOffice, например (уведомление "Набор символов: Unicode UTF-8"):

Opening test.csv in LibreOffice

Возможно, вы используете Latin-1. Вот что вы получите при использовании Latin-1 вместо UTF-8 в качестве входных данных настроек кодирования (в LibreOffice еще раз):

enter image description here

+0

Ого, ты герой. Я никогда не понимал, что проблема может быть успешной. О, я чувствую себя таким глупым ха-ха. Для всех, кто сталкивается с этим вопросом. Tldr: импортирует данные в excel (в меню данных на ленте) и переключает Windows (ANSI) или что-то еще, что он включен в Unicode (UTF-8). Кажется, это трюк! – eadebruijn

Смежные вопросы