使用Scrapy爬取非拉丁语域名

3

我需要使用Scrapy爬取一些“.рф”域名下的网站。URL的结构如下:“http://сайтдляпримера.рф"(这个URL并不是真实的,只是为了举例说明)。当然,我想要爬取的网站可以通过浏览器访问。

我尝试使用start_urls属性开始爬取,例如:

start_urls = ['http://сайтдляпримера.рф']

还有 start_requests 函数:

def start_requests(self):
    return [scrapy.Request("http://сайтдляпримера.рф/", callback=self._test)]

两者都没有按照预期工作,我收到了以下控制台消息:

2016-01-01 19:02:01 [scrapy] INFO: Spider opened
2016-01-01 19:02:01 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-01-01 19:02:01 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-01-01 19:02:01 [scrapy] DEBUG: Retrying <GET http://%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84> (failed 1 times): DNS lookup failed: address '%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84' not found: [Errno -2] Name or service not known.
2016-01-01 19:02:01 [scrapy] DEBUG: Retrying <GET http://%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84> (failed 2 times): DNS lookup failed: address '%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84' not found: [Errno -2] Name or service not known.
2016-01-01 19:02:01 [scrapy] DEBUG: Gave up retrying <GET http://%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84> (failed 3 times): DNS lookup failed: address '%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84' not found: [Errno -2] Name or service not known.
2016-01-01 19:02:01 [scrapy] ERROR: Error downloading <GET http://%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84>: DNS lookup failed: address '%D1%81%D0%B0%D0%B9%D1%82%D0%B4%D0%BB%D1%8F%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B0.%D1%80%D1%84' not found: [Errno -2] Name or service not known.
2016-01-01 19:02:01 [scrapy] INFO: Closing spider (finished)

*如果有关系,我需要在基于Linux的操作系统上使用scrapy。

是否有任何解决方案?如果可能的话,由于我无法访问框架的存储库(没有处理http请求的内容被修改),是否有办法从_spider文件中解决这个问题?

1个回答

2
处理国际化域名(IDN)时,您需要使用 idna 对非 ASCII 字符的 URL 进行编码。然后,您需要将得到的字节解码为 Unicode 字符串。此外,还应该单独添加 URL 中由协议名称(例如'http://')组成的 ASCII 子字符串前缀,以便在进行 idna 编码时不会出现混淆:
'http://' + u'сайтдляпримера.рф'.encode('idna').decode('utf-8')

另请参阅此文档以获取更多细节。


当我尝试执行类似于"http://сайтдляпримера.рф".decode('utf-8').encode('idna')的操作时,出现了错误exceptions.TypeError: must be unicode, not str。然后我得到了xn--http://-8fga3bl9al3aq0crdjw9y.xn--p1ai,并且出现了NotSupported: Unsupported URL scheme 'xn--http': no handler available for that scheme的错误提示。 - Helvdan
@Helvdan 尝试倒过来:'http://сайтдляпримера.рф'.encode('idna').decode('utf-8')。这将把字节转换为Unicode字符串。 - vrs
这是同样的错误 xceptions.TypeError: must be unicode, not str,因为 'somestr'.method1().method2() 是一个链式调用。所以与您原来的答案没有区别。 - Helvdan
@Helvdan 好的,看起来问题是由于您的URL的拉丁前缀的编码引起的。请尝试这个:'http://' + 'сайтдляпримера.рф'.encode('idna').decode('utf-8')。我自己用urlopen试过了,它可以工作。希望对于scrapy也能起作用。 - vrs
你真是救命恩人。这个方法可行。你能否修改你的答案以匹配你最后的评论? - Helvdan
由于Scrapy仅支持Python 2.7,因此首先需要将字符串转换为Unicode,例如:'http://' + u'сайтдляпримера.рф'.encode('idna')。我敢打赌您在Python 3.x上测试了您的示例。 - Helvdan

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