爬虫实战| 1宅男女神(秀人网专区)—让人心情愉悦的图片爬取 ![通俗易懂]

爬虫实战| 1宅男女神(秀人网专区)—让人心情愉悦的图片爬取 ![通俗易懂]目标是宅男女神的美女图片板块下的秀人板块,页面上全部是该网站收录的美女图片分类,大概浏览了一下,发现各个杂志社的图片(妹子)质量最高,其中以秀人为首,所以决定爬取所有秀人板块下的图片.目标网页截图该网页这里显示只有5页,后面的页面在点击下一页后出现.为了过审还是打码了,本来都是穿着衣服的正经妹妹,兄弟们可别误会了~首先利用Chrome抓包第一步先利用抓包工具来判断我们要爬取的网站是动态数据还是静态数据.这里可以清楚的看到,当我们发起请求之后,所有我们需要的东西都已经加载

大家好,又见面了,我是你们的朋友全栈君。

目标是宅男女神的美女图片板块下的秀人板块, 页面上全部是该网站收录的美女图片分类, 大概浏览了一下, 发现各个杂志社的图片(妹子) 质量最高, 其中以秀人为首, 所以决定爬取所有秀人板块下的图片.

目标网页截图

在这里插入图片描述
该网页这里显示只有5页, 后面的页面在点击下一页后出现.
为了过审还是打码了, 本来都是穿着衣服的正经妹妹, 兄弟们可别误会了~

首先利用Chrome抓包

第一步先利用抓包工具来判断我们要爬取的网站是动态数据还是静态数据.

这里可以清楚的看到,当我们发起请求之后, 所有我们需要的东西都已经加载并缓存好了, 并没有什么反爬措施, 这一步分析后,我们可以直接写代码,看看我们分析的对不对.

在这里插入图片描述

from lxml import etree
import os
import requests
headers = { 
   
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
}

response = requests.get('目标网址', headers=headers)
# 这里直接拿会全部是乱码, encoding成utf-8显示正常
response.encoding = 'utf-8'
page_text = response.text
print(page_text)

在这里插入图片描述

发现确实是我们需要的网页信息, 现在就可以对页面进行分析, 用xpath拿到我们想要的数据
发现我们每个妹妹都在li标签里, 并且需要拼接的url和title也可以在li标签里找到.
在这里插入图片描述

from lxml import etree
import os
import requests
# 该网站没什么反爬手段, 直接用最简单的header反而效果好
headers = { 
   
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
}

response = requests.get('目标网址', headers=headers)
# 这里直接拿会全部是乱码, encoding成utf-8显示正常
response.encoding = 'utf-8'
page_text = response.text
print(page_text)

tree = etree.HTML(page_text) # 
li_list = tree.xpath("//div[@id='listdiv']//li")

for li in li_list:
    img_list = []
    img_dict = { 
   }
    task_list = []
	# 拼接每个妹妹的url, 并给每个妹妹创建一个文件夹
    box_url = host + li.xpath('.//div[2]/a/@href')[0]
    file_name = li.xpath('.//div[2]/a/text()')[0]
    if not os.path.exists('./' + file_name):
        os.mkdir(file_name)

详情页分析

现在主页面的信息我们都已经拿到了, 下一步就是进入每一个妹妹详情页面, 去下载图片
在这里插入图片描述

对详情页面分析, 发现每一页都会有三张图片, 并且下面需要翻页, 经测试如果翻到最后一页再点下一页会跳转到第一页, 这里找发现在第一页会显示每个妹妹图集里有多少张图
在这里插入图片描述
用xpath拿出来, 用正则把数字提取出来.到这一步我们的页面分析已经结束了, 直接上代码, 因为这么写下载速度很慢, 所以代码有几个版本, 包括线性的和协程的来对比和优化.

线性翻页下载图片

from lxml import etree
import os
import requests
# 该网站没什么反爬手段, 直接用最简单的header反而效果好
headers = { 
   
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
}
host = '目标网站host'
response = requests.get('目标网址', headers=headers)
# 这里直接拿会全部是乱码, encoding成utf-8显示正常
response.encoding = 'utf-8'
page_text = response.text
print(page_text)

tree = etree.HTML(page_text) # 
li_list = tree.xpath("//div[@id='listdiv']//li")

for li in li_list:
    img_list = []
    img_dict = { 
   }
    task_list = []
	# 拼接每个妹妹的url, 并给每个妹妹创建一个文件夹
    box_url = host + li.xpath('.//div[2]/a/@href')[0]
    file_name = li.xpath('.//div[2]/a/text()')[0]
    if not os.path.exists('./' + file_name):
        os.mkdir(file_name)
	
	# 这里进入详情页
    page_detail = requests.get(url=box_url, headers=headers).text
    detail_tree = etree.HTML(page_detail)
	# 拿到一个图集中有多少图片的信息
    NumbersOfImage = int(re.findall('(\d+)', (detail_tree.xpath('//*[@id="dinfo"]/span/text()')[0]))[0])
	
	# 下载图片(如果图片列表里不到最大图片数量就一直翻页下载)
    while len(img_list) != NumbersOfImage:
    	# 因为每页三张, 用一个for loop解析下载
        for i in detail_tree.xpath('//*[@id="hgallery"]/img'):
        	img_dict = { 
   }
            img_dict['title'] = './' + file_name + '/' + i.xpath('./@alt')[0] + '.jpg'
            img_dict['src'] = i.xpath('./@src')[0]
			# 利用requests content下载到二进制数据, 并保存
            bytes_img = requests.get(url=img_dict['src'], headers=headers).content
            with open(img_dict['title'], 'wb') as fp:
                 fp.write(bytes_img)
                 
            img_list.append(img_dict)
            print(img_dict['title'], "下载完成", img_dict['src'])
            
            
		# 翻页部分, 利用xpath拿到下一页标签中的url 与host进行拼接,形成下一页的url
        next_page = host + detail_tree.xpath('//*[@id="pages"]/a[last()]/@href')[0]
        new_page_detail = requests.get(url=next_page, headers=headers).text
        new_page_detail_tree = etree.HTML(new_page_detail)
        detail_tree = new_page_detail_tree

        print(next_page)

在这里插入图片描述
在这里插入图片描述

这里拿到了我们想要的结果, 每页下载图片, 然后翻页, 但是这么下载的速度实在是太慢了, 一个妹妹的全部图集一张一张的下载完, 全站的图片不知道哪年才能拿到
在这里插入图片描述
这里这个妹妹图片只有35张耗时17秒, 大部分妹妹的图集都超过70张, 所以现在想办法用asyncio协程来优化一下下载速度

第一次优化

from lxml import etree
import os
import requests
import re
import time
import asyncio
import aiohttp

# 协成下载
# asyncio不支持requests, 所以这里要用到aiohttp来下载, 和requests用法相似
sem = asyncio.Semaphore(20)
async def down_load(path, url):
    with(await sem):
        async with aiohttp.ClientSession() as sess:
            async with await sess.get(url=url, headers=headers) as response:
                img_bytes = await response.read()

                with open(path, 'wb') as img:
                    img.write(img_bytes)

                print(path, " 下载成功 ", url)



# 该网站没什么反爬手段, 直接用最简单的header反而效果好
headers = { 
   
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
}
host = '目标网站host'

response = requests.get('目标网站', headers=headers)
# 这里直接拿会全部是乱码, encoding成utf-8显示正常
response.encoding = 'utf-8'
page_text = response.text

tree = etree.HTML(page_text)  #
li_list = tree.xpath("//div[@id='listdiv']//li")

for li in li_list:
    img_list = []
    img_dict = { 
   }
    task_list = []
    # 拼接每个妹妹的url, 并给每个妹妹创建一个文件夹
    box_url = host + li.xpath('.//div[2]/a/@href')[0]
    file_name = li.xpath('.//div[2]/a/text()')[0]
    if not os.path.exists('./' + file_name):
        os.mkdir(file_name)

    # 这里进入详情页
    page_detail = requests.get(url=box_url, headers=headers).text
    detail_tree = etree.HTML(page_detail)
    # 拿到一个图集中有多少图片的信息
    NumbersOfImage = int(re.findall('(\d+)', (detail_tree.xpath('//*[@id="dinfo"]/span/text()')[0]))[0])

    # 下载图片(如果图片列表里不到最大图片数量就一直翻页下载)
    while len(img_list) != NumbersOfImage:
        # 因为每页三张, 用一个for loop解析下载
        for i in detail_tree.xpath('//*[@id="hgallery"]/img'):
            img_dict = { 
   'title': './' + file_name + '/' + i.xpath('./@alt')[0] + '.jpg', 'src': i.xpath('./@src')[0]}
            # 利用requests content下载到二进制数据, 并保存
            # bytes_img = requests.get(url=img_dict['src'], headers=headers).content
            # with open(img_dict['title'], 'wb') as fp:
            # fp.write(bytes_img)

            img_list.append(img_dict)

        # 翻页部分, 利用xpath拿到下一页标签中的url 与host进行拼接,形成下一页的url
        next_page = host + detail_tree.xpath('//*[@id="pages"]/a[last()]/@href')[0]
        new_page_detail = requests.get(url=next_page, headers=headers).text
        new_page_detail_tree = etree.HTML(new_page_detail)
        detail_tree = new_page_detail_tree
        print(next_page)

	# 建立协程任务
    loop = asyncio.get_event_loop()
    for img_url in img_list:
        c = down_load(img_url['title'], img_url['src'])
        task = asyncio.ensure_future(c)
        # task.add_done_callback(parse)
        task_list.append(task)
    loop.run_until_complete(asyncio.wait(task_list))
    
    print("单个妹妹图集耗时: ", time.time() - start)
    exit()

在这里插入图片描述
这里发现如果用协成来下载的话, 速度比之前快很多, 变成了4秒钟左右, 但是翻页等操作还是线性的,还是会占用大块的时间, 现在想办法把对一个页面里所有妹妹的图集请求变成协成的, 最终代码如下

最终版本

import requests
import time
import asyncio
import aiohttp
from lxml import etree
import re
import os

host = '目标网站host'

headers = { 
   
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'
}

sem = asyncio.Semaphore(20)


async def RealDownLoad(img_url, filename):
    with(await sem):

        async with aiohttp.ClientSession() as sess:
            for url in img_url:
                async with await sess.get(url=url['url'], headers=headers) as response:
                    img_bytes = await response.read()
                    with open('./'+filename + '/' + url['path'], 'wb') as img:
                        img.write(img_bytes)
                    print(url)


async def DownLoad(page_url, filename):
    img_url = []
    for page in page_url:
        async with aiohttp.ClientSession() as sess:
            async with await sess.get(url=page, headers=headers) as response:
                page_detail = await response.text()
                detail_tree = etree.HTML(page_detail)
                for i in detail_tree.xpath('//*[@id="hgallery"]/img'):
                    img = { 
   'url': i.xpath('./@src')[0], 'path': i.xpath('./@alt')[0] + '.jpg'}
                    img_url.append(img)
    return await RealDownLoad(img_url, filename)


async def GetInDetailPage(boxes):
    page_url = []

    for i in range(15):
        page_url.append(boxes['url'] + str(i) + ".html")

    return await DownLoad(page_url, boxes['file_name'])


async def main():
    tasks = []
    url = '目标网站'
    response = requests.get(url=url, headers=headers)
    response.encoding = 'utf-8'
    page_text = response.text

    box_url_list = []
    box_task_list = []
    tree = etree.HTML(page_text)
    li_list = tree.xpath("//div[@id='listdiv']//li")

    for li in li_list:
        box = { 
   }
        box_url = host + li.xpath('.//div[2]/a/@href')[0]
        file_name = li.xpath('.//div[2]/a/text()')[0]

        if not os.path.exists('./' + file_name):
            os.mkdir(file_name)

        box['url'] = box_url
        box['file_name'] = file_name
        box_url_list.append(box)
    for boxes in box_url_list:
        c = GetInDetailPage(boxes)
        tasks.append(asyncio.ensure_future(c))

    await asyncio.wait(tasks)

loop = asyncio.get_event_loop()
start = time.time()
loop.run_until_complete(main())
print("用时: ", time.time()-start)

exit()

在这里插入图片描述
最终版本下载了目标页面宅男女神->美女图片->秀人网 下所有妹妹的图集(20个图集), 总用时不到30秒钟.
这段代码是只爬了”目标网址”的第一页, 没加翻页的函数, 有想法的朋友可以自己加一个翻页的方法.

其实这样类型的爬虫用scrapy框架中的crawl spider是最好的, 想看的朋友可以给我留言.

总结

写的不是很好, 包括对asyncio库的运用, 整体代码的封装等等, 后面还会持续更新爬虫方面的实例, 希望能给也在学习爬虫相关知识的朋友一点点启发, 喜欢的朋友也请点个赞吧,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/136799.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 宽度 & 深度学习 特点对比

    宽度 & 深度学习 特点对比宽度&深度学习特点对比推荐系统模型介绍实验过程与实验结果实验总结  为了提高神经网络的性能,是应该增加宽度呢?还是应该增加深度呢?增加宽度和增加深度各有什么样的效果呢?本文对论文《Wide&DeepLearningforRecommenderSystemsHeng-Tze》中关于宽度模型和深度模型的对比实验进行介绍。推荐系统  本论文基于推荐系统,推荐系…

  • goland 最新激活码(破解版激活)「建议收藏」

    goland 最新激活码(破解版激活),https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • 网页服务器停止响应是什么意思_次数限制

    网页服务器停止响应是什么意思_次数限制1.根据以往的经验以为是缓冲池的缘故。于是我新建一个缓冲池之后(尽量大的配置)发现问题依旧2.修改查询语句 select*fromtable改成selecttop500*fromtable发现问题依旧 没有办法于是认真的查看程序 结果发现自己的低级错误少加一句rs.movenext加上之后问题解决  根据这次的问题心得是:1.发现问题先看看

    2022年10月21日
  • 键盘与计算机连接,罗技键盘怎么连接电脑?原来连接的方式这么简单!「建议收藏」

    键盘与计算机连接,罗技键盘怎么连接电脑?原来连接的方式这么简单!「建议收藏」现在科技的发展已经让我们拥有越来越方便电子的工具,他们在生活中会帮助我们更快捷方便的达到目的,可以说科技创造了新的生活与理念。很多人也都逐渐让自己的生活更加接近现代技术的发展,比如我们会通过在生活中购买很多的智能家居的方式,让自己感受科技的力量。其实除了智能家居,我们常使用的电脑就是一种非常智能和先进的科技。而与电脑相关的键盘也被开发的越来越智能和先进,我们的使用的可能过程可能就会存在很多的问题,…

    2022年10月16日
  • MySQL允许root远程登录[通俗易懂]

    MySQL允许root远程登录[通俗易懂]新安装的数据库只能localhost访问??是不是很苦逼下面介绍如何允许远程访问root1.“试一下”能否远程登录>mysql-uroot-p-h10.0.42.180答案是否定的。那就开始进行设置吧2.登录数据库,默认本地访问>mysql-uroot-p3.切换mysql数据库mysql>usem…

  • matlab三维画图

    matlab三维画图

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号