500lines之crawler学习(三)

回到最初的话题,为什么我们通过:

python -q crawl.py xkcd.com

上面命令在控制台运行,啥结果都没有,是因为在第一篇博客(crawler学习(一))中,分析过-q会让日志级别变低(level=0),设置代码(crawl.py中)如下:
 

levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG]
logging.basicConfig(level=levels[min(args.level, len(levels)-1)])

所以我们要查看日志信息,就不要加-q命令(或者加-v)提高日志显示级别。我们再运行:

python crawl.py xkcd.com

结果如下:

500lines之crawler学习(三)

控制台总算出现了两条日志信息,然后就卡住了,什么结果也没有。这显然不是我们想要的结果。但是我们通过日志,还是能得出重要的信息,那就是打印第二行的日志以后,我们的程序在某个地方卡住了。所以先找到第二条日志打印的地方:

500lines之crawler学习(三)

                                                                       (图一)

在crawling.py中,我们找到第二条打印日志的地方,通过每行打印的方式,再结合(crawler学习(一))中urljoin函数的用法,我们初步判断应该是urljoin函数的地方出了错。

但是什么错,为什么没在控制台显示出来呢?还是在crawling.py中:

500lines之crawler学习(三)

可以看出,代码采用的是try...finally结构,没有捕获异常,更不要说抛出来了。所以我们需要加点代码:

500lines之crawler学习(三)

运行结果如下:

500lines之crawler学习(三)

                                          (图二)

可以看出,我们的代码起了效果,获得了抛出的异常信息。虽然这个信息有点用,但是我仍然不能确定是什么原因导致的这个错误,所以我把上面(图一)中urls所有值都打印出来,然后与url(https://xkcd.com/)进行urljoin操作,结果都正确,没出现异常。经过仔细观察上面的(图二),发现response.url并不是“https://xkcd.com/”,而是:

URL('https://xkcd.com/')

不错,这个玩意居然是一个URL对象,一个字符串与一个URL对象比较,当然会出错啦。那怎么将URL变成字符串呢?

我们只知道它是一个URL对象,并不知道URL对象里面有些什么方法?通过aiohttp文档,我找到了以下网页:

https://yarl.readthedocs.io/en/stable/api.html#yarl.URL

列出重点:

>>> url = URL('http://εμπορικόσήμα.eu/путь/這裡')
>>> str(url)
'http://xn--jxagkqfkduily1i.eu/%D0%BF%D1%83%D1%82%D1%8C/%E9%80%99%E8%A3%A1'
>>> url.human_repr()
'http://εμπορικόσήμα.eu/путь/這裡'

可以看出可以通过str()函数对URL编码成一个字符串,或者通过human_repr()函数返回字符串形式。由于xkcd.com都是些英文网页,所以我直接采用了str()形式:

for url in urls:
    normalized = urllib.parse.urljoin(str(response.url), url)
    defragmented, frag = urllib.parse.urldefrag(normalized)
    if self.url_allowed(defragmented):
         links.add(defragmented)

再运行程序,控制台会出现发送请求后得到的各种日志信息!

然而,即便如此,此crawler项目也还有许多问题需要解决。此文算是迈出重要一步!!!