Scrapy 搜狗词库爬虫

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AmazingUU/article/details/83421893

引言

最近在学习Python爬虫,这里推荐一个入门爬虫的博客系列
https://github.com/Ehco1996/Python-crawler
博主写的对新手很友好,很适合入门。

我写这篇文章的目的是记录一下在学习他的
搜狗词库抓取&解析 中遇到的问题。

思路

和原文不同的是,我是采用Scrapy实现,并且考虑到后面对词库关键词的解析不属于爬虫,所有我就只实现了搜狗词库爬取,没有做解析。另外原文中cate表只是作为中转,我就没有存储,所以我只建了一个表detail。

  1. 建表detail,字段url、filename、cate1、cate2、create_time
  2. 从初始url中解析全部一级分类url,再从一级分类url中解析二级分类url
  3. 从二级分类url中解析出每一个二级分类的页数,将二级分类url和每一个二级分类的页数拼接成新的url,再从新的url中解析出下载地址和标题
  4. 将下载地址、标题、一级分类和二级分类一并存入detail表
  5. 从detail表中取出所有下载地址,下载文件到本地

问题

1. 一级分类标题文字为图片形式,获取不到

分析搜狗词库发现,它的一级分类里的文字是图片中的文字,爬取不到。没办法,只能写成固定的常量列表了,还好一级分类应该不会变动。
一级分类

2. 下载地址太长,写不进数据库

下载地址保存到Mysql时报错 1406, “Data too long for column ‘url’ at row 1”
参考如下文章解决
mysql报错:1406, "Data too long for column

3. 文件下载

项目里还涉及到文件下载,查资料了解到scrapy的文件下载是通过FilesPipeline实现的
下载及处理文件和图片
官方文档说的很详细,需要注意的有三点

(1) get_media_requests()在不重写的情况下,处理的url固定为item[‘file_urls’],且要求传递过来的为一系列url列表。所以没有其他要求的话,直接在item中定义该字段,pipeline中创建类继承下FilesPipeline即可。
本项目中传递的url为单个string,不是列表,所以重写了该方法

(2) 下载的默认文件名为文件的SHA1值,需要重命名。查看文档发现file_path()返回文件的绝对路径,需要在这里将文件重命名,但是这个方法里并没有item参数,如何拿到filename呢?
仔细看file_path()参数里有一个request,这个request就是get_media_requests()里返回的,只需要将filename给request的meta即可

(3) 注意setting里的FILES_STORE为绝对路径。这是文件的下载目录,需要设为绝对路径
具体代码如下:

class SogouWordFilePipeline(FilesPipeline):  # 下载文件
    def get_media_requests(self, item, info):
        # 该方法不重写的话为:
        # for file_url in item['file_urls']:
        #     yield scrapy.Request(file_url)
        # 即如果item中定义了file_urls字段,且有使用FilesPipeline的类,该字段自动进入FilesPipeline中处理
        # 但是要求item['file_urls']为列表,我这里的下载url不是列表而且需要处理文件名问题,所以就重写了一下
        yield scrapy.Request(item['url'], meta={'filename': item['filename']})

    def item_completed(self, results, item, info):  # 下载完成时调用
        file_paths = [x['path'] for ok, x in results if ok]
        if not file_paths:
            print('下载失败')
            raise DropItem("Item contains no files")
        # item['file_paths'] = file_paths
        print('下载成功')
        return item

    def file_path(self, request, response=None, info=None):  # 文件名
        filename = request.meta['filename']  # 这里request的meta来自get_media_requests()
        basedir = os.getcwd()
        download_dir = os.path.join(basedir, 'download')
        path = os.path.join(download_dir, filename + '.scel')
        return path

总结

利用scrapy框架的好处就是不用自己考虑多线程的问题了,而且也有专门的日志记录,所以框架是挺方便的。
下篇文章讲讲python里的多线程问题。

项目地址

https://github.com/AmazingUU/Scrapy-sogou_spider
上面是项目地址,觉得还可以的话,给个star哦

猜你喜欢

转载自blog.csdn.net/AmazingUU/article/details/83421893