python爬虫(三)——多线程+正则匹配下载图片(wallheaven图片网站)

多线程+正则匹配下载图片(wallheaven图片网站)

1. wallheaven 壁纸网站

wallheaven
这个网站的图片是提供下载的,在壁纸类别之中质量非常高,包括了很多的高清图片。
详细情况可访问其主页页面:wallheaven

2、分析网页架构

1)获取全部页面的地址分析
网页主页地址为:

https://wallhaven.cc/

输入关键词china进行查询后,地址变为:

https://wallhaven.cc/search?q=china

下滑到第二页之后,地址变为:

https://wallhaven.cc/search?q=china&page=2

那么我们就得到了一个通用的地址访问格式:

https://wallhaven.cc/search?q={}&page={}

其中两个中括号之中分别填写关键词和页数


2)获取全部图片的地质
查看一张图片的url地址

图片地址

https://th.wallhaven.cc/small/mp/mp3dwm.jpg

但是点开图片再单独查看图片可见其地址为:
详细地址

https://w.wallhaven.cc/full/mp/wallhaven-mp3dwm.jpg

对比前后两张图片,可以明显地发现首页展示的图片画质非常差,而且经过压缩之后大小变形了,用来做壁纸或者其他用途都很有限。所有我们通向希望得到详细页面中的高清页面。我们至此有两种方案可以获取得到图片的地址:

  1. 从首页进入图片页面,在图片页面获得图片下载地址
  2. 从首页获得低清晰度图片下载地址,经过地址重组获得高清图片的下载地址

这里我选择第二种方法,以便捡一捡长时间不用的正则表达

3、编码实现

1) 导入相关函数库

import os
import requests
import redis
from lxml import etree
import urllib.request
import time
import threading
from queue import Queue
import re

2) 我后面打算使用redis作为中间件保存url等信息,暂时还没有使用,先定义好(可略过)

pool = redis.ConnectionPool(host='localhost',port=6379,decode_responses=True)
r = redis.Redis(connection_pool=pool)
print(r.ping())

3)主要函数及爬取过程
注意:

  • headers 中的内容根据自己的情况进行填写
  • Producer类:获取全部的img地址
  • consumer类:下载img
  • 我这里使用的关键词是’anime’,可以通过input来进行交互下载
  • 如果有什么错误或者认为不太正确的地方请联系我
Headers = {
'authority': 'wallhaven.cc',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'cookie': '',  # 请写上自己的
'referer': 'https://wallhaven.cc/',
'user-agent': '' # 请修改为自己的
}
class Producer(threading.Thread):
    def __init__(self,page_queue,img_queue,*args,**kwargs):
        super(Producer, self).__init__(*args, **kwargs)
        self.page_queue = page_queue
        self.img_queue = img_queue
    
    def run(self):
        while True:
            if self.page_queue.empty():
                break
            page_url = self.page_queue.get()
            page_text = self.deal_url(page_url)
            self.parse_indexPage(page_text)
                
    def deal_url(self,url):
        response = requests.get(url,headers=Headers)
        response.encoding= response.apparent_encoding
        return response.text
    
    def parse_indexPage(self,text):
        html = etree.HTML(text)
        wallpaper_urls = html.xpath("//img[@alt='loading']/@data-src")
        for url in wallpaper_urls:
            url = url.replace('th','w',1) # 替换第一个th为w
            url = url.replace('small','full') # 替换small为full
            last_urlTail = re.search(r'[^/]+(?!.*/)',url).group() #正则获取url最后一个/后的内容
            new_urlTail = 'wallhaven-'+last_urlTail
            url = url.replace(last_urlTail,new_urlTail) #重构网址
            self.img_queue.put((new_urlTail,url)) 

class Consumer(threading.Thread):
    def __init__(self,page_queue,img_queue,*args,**kwargs):
        super(Consumer,self).__init__(*args,**kwargs)
        self.page_queue = page_queue
        self.img_queue = img_queue
    
    def run(self):
        while True:
            if self.img_queue.empty() and self.page_queue.empty():
                break
            img_name,img_url = self.img_queue.get()
            self.save_img(img_name,img_url)

    def save_img(self,img_name,img_url):
        root= './3_figure/'
        path = root+img_name
        try:
            if not os.path.exists(root):
                os.mkdir(root)
            if not os.path.exists(path):
                read_figure = requests.get(img_url)
                with open(path,'wb')as f:
                    f.write(read_figure.content)
                    f.close()
                    print(path+" save ok!")
            else:
                print('文件已保存')
        except:
            print("文件爬取失败")  

def main():
    base_url = 'https://wallhaven.cc/search?q={}&page={}'
#     keyword = input("please input the keyword")
    keyword = 'anime'
    page_queue = Queue(20)
    img_queue = Queue(200)
    page_num = 10
    for x in range(1,page_num+1):
        url = base_url.format(keyword,x)
        page_queue.put(url)
        print(url)
        
    for x in range(5):
        t = Producer(page_queue,img_queue)
        t.start() 
        
    for x in range(5):
        t = Consumer(page_queue,img_queue)
        t.start()
            
if __name__ == '__main__':
    main()
4、结果视图

我下载了10页的图片,每页24张图片,共计240张:
结果1
打开其中的一张图片:
结果2
看起来画质还不错。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留小星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值