irpas技术客

【爬虫作业】使用scrapy批量爬取头像,并通过redis进行去重_仙草哥哥

网络 6844

前情提要

小伙伴们期待已久的爬虫作业栏目,终于又更新啦。本次的程序,是自动设置头像的爬虫程序的一种升级应用版本,基本的思路是,通过遍历用户头像,就可以保存大量的头像了

至于保存到哪里呢?在这个程序的准备工作中考虑过保存到第三方图床上或者是使用oss对象存储功能。不过最后还是采用了直接保存为文件。下次有机会的话,再用其他方式吧

实现分析

首先,第一个部分就是发起请求,然后保存图片。这个功能在上一次的程序中已经实现过了

def save_img(qq_number): base_url = "aHR0cHM6Ly9xbG9nbzQuc3RvcmUucXEuY29tL3F6b25lLw==" url = b64decode(base_url).decode() + str(qq_number) + "/" + str(qq_number) + "/" + "640" headers = {"user-agent": "Mozilla/5.0"} r = requests.get(url, headers=headers) with open(str(qq_number) + ".png", "wb") as f: f.write(r.content)

问题在于,如果批量爬取头像的话,就不能采用这种直接保存的方式。主要原因在于,在此期间,我们也会遇到大量的重复头像和默认头像,如果我们把这些重复的内容都保存一次的话,无疑会浪费很多的空间,而且在后期的使用和处理上也是非常糟糕的,因此,我们必须引入去重的功能

首先呢,我们先计算这个图片的哈希值,然后把这个值存起来,等到爬下一个图片的时候,用下一个图片的哈希值和当前图片的值进行对比。如果相同,就放弃这个图片

如果只使用python的内置方法的话,考虑使用集合会是一个好的选择。如果为了保持持久化,我们还可以在程序结束的时候,把集合中的内容保存到文件中,下次运行时再读取回来

当然,更好的选择就是,配置一个redis数据库,将图片的哈希值保存到redis数据库中,这样可以使的程序的性能更高,整体思路就是这样的

完整代码展示

spider.py,初始化图片地址列表,发起请求,得到响应

class FaceSpider(scrapy.Spider): name = 'face' def start_requests(self): base_url = "aHR0cHM6Ly9xbG9nbzQuc3RvcmUucXEuY29tL3F6b25lLw==" for number in range(Q_START, Q_END): url = b64decode(base_url).decode() + str(number) + "/" + str(number) + "/" + "640" yield scrapy.Request( url=url, callback=self.parse, meta={"number": number} ) def parse(self, response): item = ImgItem() item["number"] = response.meta["number"] item["img"] = response.body yield item

items.py,定义保存的item

class ImgItem(scrapy.Item): img = scrapy.Field() number = scrapy.Field()

pipelines.py,主要有两个任务,去重以及保存图片

class RedisPipeline: def __init__(self, redis_host, redis_port, redis_db, redis_password): self.host = redis_host self.port = redis_port self.db = redis_db self.password = redis_password @classmethod def from_crawler(cls, crawler): return cls( redis_host=crawler.settings.get("REDIS_HOST"), redis_port=crawler.settings.get("REDIS_PORT"), redis_db=crawler.settings.get("REDIS_DB"), redis_password=crawler.settings.get("REDIS_PASSWORD"), ) def open_spider(self, spider): self.redis = Redis(host=self.host, port=self.port, db=self.db, password=self.password) def process_item(self, item, spider): hash = md5() hash.update(item["img"]) h = hash.hexdigest() if not self.redis.sismember("img", h): self.redis.sadd("img", h) return item else: return DropItem("already exists") class ImgsDownloadPipeline: def __init__(self, img_path): self.img_path = img_path @classmethod def from_crawler(cls, crawler): return cls( img_path=crawler.settings.get("IMG_PATH") ) def open_spider(self, spider): if not exists(self.img_path): mkdir(self.img_path) def process_item(self, item, spider): if isinstance(item, DropItem): return item save_path = join(".", self.img_path, str(item["number"]) + ".png") with open(save_path, "wb") as f: f.write(item["img"]) return item

settings.py,配置文件,主要包括redis数据库的配置,以及图片列表初始化的配置

BOT_NAME = 'imgs' SPIDER_MODULES = ['imgs.spiders'] NEWSPIDER_MODULE = 'imgs.spiders' USER_AGENT = 'Mozilla/5.0' ROBOTSTXT_OBEY = True IMG_PATH = "img_save" Q_START = 550000000 Q_END = 550001000 REDIS_HOST = "localhost" REDIS_PORT = 6379 REDIS_DB = 0 REDIS_PASSWORD = "" ITEM_PIPELINES = { "imgs.pipelines.RedisPipeline": 300, "imgs.pipelines.ImgsDownloadPipeline": 301, } AUTOTHROTTLE_ENABLED = True AUTOTHROTTLE_TARGET_CONCURRENCY = 1 CONCURRENT_REQUESTS_PER_DOMAIN = 1 DOWNLOAD_DELAY = 1

完整的程序以及使用说明已经上传至github,这里是该项目github的链接地址

如需下载,可以通过git直接下载

git clone https://github.com/sagegrass/spider03.git

如果可以的话点个关注,每天带你使用新的爬虫程序哦!


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #并通过redis进行去重