ActiveMQ swift dataframe file servlets concurrency module sas 建筑资质 vue前端框架 vue遍历 bootstrap后台管理 建站一条龙 electron教程 oracle一键卸载工具 mysql查看锁表 python的数据类型 python安装教程 python编程教程 python基础教程 windows安装python环境 java发邮件 java文件路径 javascript实例 rendercontrol Ext2Fsd 路由器辐射大吗 键盘模拟器 sim卡注册失败 为什么英雄联盟无法连接服务器 pr蒙版 php小数点保留2位 挑战程序设计竞赛 小程序游戏源码 电脑待机费电吗 魔兽天龙八部 cad2008汉化包 类似迅雷的下载软件 ps二寸照片制作教程 人马上单天赋
当前位置: 首页 > 学习教程  > python

【Python aiohttp异步爬虫】批量爬取电脑壁纸

2021/2/6 23:24:13 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

寒假在家,实在无事可做,就找到了崔庆才爬虫52讲的课程,巩固一下爬虫知识,最近也是学到了异步爬虫,本来想按照视频教的案例实践一下就可以了,没想到案例网站证书过期了,没办法进行实践&#xff0…

寒假在家,实在无事可做,就找到了崔庆才爬虫52讲的课程,巩固一下爬虫知识,最近也是学到了异步爬虫,本来想按照视频教的案例实践一下就可以了,没想到案例网站证书过期了,没办法进行实践,只能去找别的网站实践了。
一开始学习爬虫就是看到别人爬取美女图片(主要是因为图片网站没有什么反爬,绝对不是冲着图片去的),就是刚开始都是一张一张下载的,速度及其的慢,既然学了异步爬虫就想着能不能异步爬取图片加速图片的爬取。
说干就干,直接百度搜索电脑壁纸,随机选取“幸运儿”。
有请我们的幸运儿:彼岸图网

分析

我们直接进入4K动漫壁纸页面,分析初始页面的url,可以看到页面的url在这里插入图片描述
翻页观察一下
在这里插入图片描述
多翻几个页面,很明显的可以总结出页面url的变化规律:http://pic.netbian.com/4kdongman/index_{page}.html
可以看到初始url还是很简单的。

接下来我们分析一下拿到图片的链接
在这里插入图片描述
这里我先选择了直接打开scr里面图片链接,发现图片非常的模糊,而且非常的小,这肯定是不适合做我们的电脑壁纸。

继续往下分析,随便打开一个图片链接
在这里插入图片描述
发现刚好是初始地址加上面我们分析获得的href属性组成的。
即http://pic.netbian.com{id}.html
再分析一下源代码
在这里插入图片描述
再次定位到src属性,拼接上网站的初始url,浏览器打开图片,果然是我们想要的图片地址。

接下来用代码实现就很简单了,我们首先请求初始页面,提取出详情页面的url,再请求详情页面,解析详情页面拿到图片的链接和地址就可以了。(我这里用的是re暴力匹配的,也可以用bs4,lxml等方法)

代码实现

import asyncio
import re
import aiohttp
import logging
import os

# 定义日志文件
logging.basicConfig(level=logging.INFO,format="%(asctime)s-%(levelname)s:%(message)s")

# 定义初始页的url
INDEX_URL = "http://pic.netbian.com/4kdongman/index_{page}.html"
# 定义详情页的url
DETAIL_URL = "http://pic.netbian.com{id}.html"
# 定义壁纸的初始url
IMG_URL = 'http://pic.netbian.com{img_url}'

# 定义将要爬取的页数
PAGE_NUMBER = 147
# 定义爬取的信号量
CONCURRENCY = 5

# 构造存储壁纸的路径
PATH = "D:\img"
if not os.path.exists(PATH):
    os.mkdir(PATH)

# 初始化信号量
semaphore = asyncio.Semaphore(CONCURRENCY)
session = None

# 此函数的功能是定义一个基本的抓取方法,传入url即可返回网页的源代码
async def scrape_api(url):
    async with semaphore:
        try:
            logging.info('scraping %s',url)
            async with session.get(url) as response:
                return await response.text()
        except aiohttp.ClientError:
            logging.error('error occurred while scraping %s',url,exc_info=True)


# 此函数的功能是构造初始页的url
async def scrape_index(page):
    url = INDEX_URL.format(page=page)
    return await scrape_api(url)

# 此函数的功能是定义详情页的url,并解析详情页,拿到img的url和名字
async def scrape_detail(id):
    url = DETAIL_URL.format(id=id)
    data = await scrape_api(url)
    IMG = re.search('<img src="(.*?)" data-pic',data,re.S).group(1)
    img_url = IMG_URL.format(img_url=IMG)
    name = re.findall('<img.*?title="(.*?)"',data,re.S)[0]
    return await scrape_save_img(img_url,name)

# 此函数的功能是访问图片的链接,并返回二进制数据
async def scrape_save_img(url,name):
    async with semaphore:
        try:
            logging.info('scraping %s',url)
            async with session.get(url) as response:
                img = await response.read()
                return await save_data(img,name)
        except aiohttp.ClientError:
            logging.error('error occurred while scraping %s',url,exc_info=True)

# 此函数的功能是存储图片
async def save_data(img,name):
    with open(f'D:\img\\{name}.jpg',"wb") as f:
        print('正在存储图片')
        f.write(img)
        f.close()
        print('图片存储成功')

# 主函数
async def main():
    global session
    # 初始化session
    session = aiohttp.ClientSession()
    # 定义爬取列表页的所有task
    scrape_index_tasks = [asyncio.ensure_future(scrape_index(page))for page in range(2,PAGE_NUMBER+1)]
    # 调用asyncio.gather方法传入task列表,将结果赋值给result,这个result就是所有task返回结果的列表
    result = await asyncio.gather(*scrape_index_tasks)
    logging.info('result %s',result)

    # 遍历result
    for index_data in result:
        # 判断index_data是否为空,防止出现空白index_data导致程序意外终止
        if not index_data:continue
        ids = re.findall('<li><a href="(.*?).html" target="_blank"><img',index_data,re.S)[1:20]
        # 声明爬取所有详情页task组成的列表
        scrape_index_tasks = [asyncio.ensure_future(scrape_detail(id))for id in ids]
        # 调用asyncio.wait方法调用执行,也可以用gather方法,效果一样,返回结果有差异
        await asyncio.wait(scrape_index_tasks)
    # 关闭session
    await session.close()

# 程序开始运行
if __name__ == '__main__':
    # 调用异步协程
    asyncio.get_event_loop().run_until_complete(main())

代码主要是仿照着教学视频上面的风格写的(感觉视频上面的代码逻辑十分清晰,就仿照这这种风格写了),注释什么的也写的很清楚,不懂的可以自己看哈。

之后我又打开了几个网站元气壁纸,观察了一下感觉这些图片网站的结构都是一样的,标签页,加详情页的格式。
标签页:在这里插入图片描述
规则:https://bizhi.ijinshan.com/2/index_{page}.shtml

详情页:在这里插入图片描述
规则:https://bizhi.ijinshan.com/2/{id}.shtml
其中的逻辑基本都是一样的:请求初始页面,提取出详情页面的url,再请求详情页面,解析详情页面拿到图片的链接和地址。

又看了一样代码,好像改两三个地方就直接可以爬了,卧槽…
说干就干,一顿分析之后,改了三个地方,直接就可以爬取别的网站了。

# 定义初始页的url
INDEX_URL = "https://bizhi.ijinshan.com/2/index_{page}.shtml"
# 定义详情页的url
DETAIL_URL = "https://bizhi.ijinshan.com/2/{id}.shtml"
# 定义壁纸的初始url
IMG_URL = 'https://wallpaperm.cmcm.com/{img_url}'

# 定义将要爬取的页数
PAGE_NUMBER = 100
# 此函数的功能是定义详情页的url,并解析详情页,拿到img的url和名字
async def scrape_detail(id):
    url = DETAIL_URL.format(id=id)
    data = await scrape_api(url)
    IMG = re.search('<img src="https://wallpaperm.cmcm.com/(.*?)" alt="(.*?)">',data).group(1)
    img_url = IMG_URL.format(img_url=IMG)
    name = re.search('<img src="https://wallpaperm.cmcm.com/(.*?)" alt="(.*?)">',data).group(2)
    return await scrape_save_img(img_url,name)

        ids = re.findall('data-image-id="(.*?)"',index_data,re.S)

之后再次运行,成了!

哇!崔神的代码格式就是不一样,这明明就是一个代码模板啊!
感兴趣的小伙伴可以试一下别的网站。

附上
运行过程
在这里插入图片描述

在这里插入图片描述

爬取的结果

总共爬取了近万张的4K图片,用了不到一个20分钟。

PS:新人第一次发博客,不足的地方多多包涵。


本文链接: http://www.dtmao.cc/news_show_2000163.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?