小伙伴们期待已久的爬虫作业栏目,终于又更新啦。本次的程序,是自动设置头像的爬虫程序的一种升级应用版本,基本的思路是,通过遍历用户头像,就可以保存大量的头像了
至于保存到哪里呢?在这个程序的准备工作中考虑过保存到第三方图床上或者是使用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
如果可以的话点个关注,每天带你使用新的爬虫程序哦!



