Python - 10行代码集2000张美女图


Posted in Python onMay 23, 2021

一切的起点,10 行代码集美女

前奏篇

正式编写爬虫学习前,以下内容先搞定:

  • 能安装 Python 环境,例如安装 3.5 版本,可以切换为其他版本;
  • 能熟练开发工具,例如 VSCode,PyCharm;
  • 能熟练 Python 第三方库;
  • 能运行 Python 脚本文件,能输出 hello world。

有以上技能,就可以放心大胆的购买本专栏进行学习。

截止 2021 年 5 月 20 日 Python 最新版本,官网版本为 3.9.5 版本,你可以直接使用该版本,也可以使用任意 3.0 以上版本。

目标数据源分析

本次待抓取的目标地址为:
http://www.netbian.com/mei/index.htm

Python - 10行代码集2000张美女图

抓取目标:
抓取该网站的图片,目标 2000 张。

用到的 Python 框架为:
requests 库、re 模块

其它技术栈补充:
正则表达式

目标网站地址规则:

  • http://www.netbian.com/mei/index.htm
  • http://www.netbian.com/mei/index_2.htm
  • http://www.netbian.com/mei/index_3.htm

结论,列表页规则为 http://www.netbian.com/mei/index_{页码}.htm

数据范围

  1. 累计 164 页;
  2. 每页 20 条数据。

图片所在标签与页面地址
图片所在标签位置代码如下:

<li><a href="/desk/23397.htm" title="陆萱萱 白色衬衫  裙子 职业装 美女模特壁纸 更新时间:2021-04-11" target="_blank"><img src="http://img.netbian.com/file/2021/0411/small30caf1465200926b08db3893c6f35f6c1618152842.jpg" alt="陆萱萱 白色衬衫  裙子 职业装 美女模特壁纸"><b>陆萱萱 白色衬衫  裙子 职业装 美女模特壁纸</b></a></li>

页面地址为 /desk/23397.htm

整理需求如下

  1. 生成所有列表页 URL 地址;
  2. 遍历列表页 URL 地址,并获取图片详情页地址;
  3. 进入详情页获取大图;
  4. 保存图片;
  5. 得到 2000 张图片之后,开始欣赏。

代码实现时间

提前安装完毕 requests 模块,使用 pip install requests 即可,如果访问失败,切换国内 pip 源。

留个课后小作业,如何设置全局的 pip 源。

代码结构如下:

import requests

# 抓取函数
def main():
    pass

# 解析函数
def format():
    pass

# 存储函数
def save_image():
    pass

if __name__ == '__main__':
    main()

先实现 10 行代码抓美女图,举个例子,在正式开始前,需要略微了解一些前端知识与正则表达式知识。

例如通过开发者工具查看网页,得到图片素材都在 <div class="list"><div class="page"> 这两个标签中,首先要做的就是拆解字符串,取出目标数据部分。

Python - 10行代码集2000张美女图
通过 requests 对网页源码进行获取,代码如下。

# 抓取函数
def main():
    url = "http://www.netbian.com/mei/index.htm"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
    }
    res = requests.get(url=url, headers=headers, timeout=5)
    res.encoding = "GBK"
    print(res.text)

使用 requests 模块的 get 方法即可获取网页数据,其中的参数分别是请求地址,请求头,等待时间。

请求头字段中的 User-Agent,可以先使用我提供给你的内容,也可以通过开发者工具,进行获取。

在数据返回 Response 对象之后,通过 res.encoding="GBK" 设置了数据编码,该值可以从网页源码中获取到。

Python - 10行代码集2000张美女图

请求到数据源码,即开始解析数据,如果使用正则表达式,建议先对目标数据进行一些简单的裁剪工作。

裁剪字符串是 Python 中比较常规的操作了,直接编写代码即可实现。

用到的还是上文已经提及的两个字符串。

# 解析函数
def format(text):
    # 处理字符串
    div_html = '<div class="list">'
    page_html = '<div class="page">'
    start = text.find(div_html) + len(div_html)
    end = text.find(page_html)
    origin_text = text[start:end]

最终得到的 origin_text 就是我们的目标文本。

通过 re 模块解析目标文本

上文返回的目标文本如下所示,本小节的目标就是获取到图片详情页地址。

Python - 10行代码集2000张美女图
使用的技术是 re 模块,当然需要配合正则表达式进行使用,对于正则表达式,可以跟随橡皮擦一点点的接触。

# 解析函数
def format(text):
    # 处理字符串
    div_html = '<div class="list">'
    page_html = '<div class="page">'
    start = text.find(div_html) + len(div_html)
    end = text.find(page_html)
    origin_text = text[start:end]

    pattern = re.compile('href="(.*?)"')
    hrefs = pattern.findall(origin_text)
    print(hrefs)

其中 re.compile 方法中传递的就是正则表达式,它是一种检索字符串特定内容的语法结构。

例如

  • . :表示除换行符(\n\r)之外的任何单个字符;
  • *:表示匹配前面的子表达式零次或多次;
  • ?:当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的,非贪婪就是减少匹配;
  • ():分组提取用。

有这些知识之后,在回到代码中去看实现。

Python - 10行代码集2000张美女图
假设存在一个字符串:href="/desk/23478.htm",使用 href="(.*?)" 可以将其中的 /desk/23478.htm 匹配出来,括号的作用也是为了后续方便提取。

最后输出内容如下图所示。

Python - 10行代码集2000张美女图

清洗爬取结果

其中存在部分链接地址不正确,需要从列表中进行去除,本步骤使用列表生成器即可完成任务。

pattern = re.compile('href="(.*?)"')
    hrefs = pattern.findall(origin_text)
    hrefs = [i for i in hrefs if i.find("desk")>0]
    print(hrefs)

抓取内页数据

获取到列表页地址之后,就可以对图片内页数据进行获取了,这里用到的技术与前文逻辑一致。

# 解析函数
def format(text, headers):
    # 处理字符串
    div_html = '<div class="list">'
    page_html = '<div class="page">'
    start = text.find(div_html) + len(div_html)
    end = text.find(page_html)
    origin_text = text[start:end]

    pattern = re.compile('href="(.*?)"')
    hrefs = pattern.findall(origin_text)
    hrefs = [i for i in hrefs if i.find("desk") > 0]
    for href in hrefs:
        url = f"http://www.netbian.com{href}"
        res = requests.get(url=url, headers=headers, timeout=5)
        res.encoding = "GBK"
        format_detail(res.text)
        break

在第一次循环中增加了 break,跳出循环,format_detail 函数用于格式化内页数据,依旧采用格式化字符串的形式进行。

由于每页只有一张图片是目标数据,故使用的是 re.search 进行检索,同时调用该对象的 group 方法对数据进行提取。

发现重复代码了,稍后进行优化。

def format_detail(text):
    # 处理字符串
    div_html = '<div class="pic">'
    page_html = '<div class="pic-down">'
    start = text.find(div_html) + len(div_html)
    end = text.find(page_html)
    origin_text = text[start:end]
    pattern = re.compile('src="(.*?)"')
    image_src = pattern.search(origin_text).group(1)
    # 保存图片
    save_image(image_src)

保存图片部分,需要提前导入 time 模块,对图片进行重命名。

使用 requests.get 方法直接请求图片地址,调用响应对象的 content 属性,获取二进制流,然后使用 f.write 存储成图片。

# 存储函数
def save_image(image_src):
    res = requests.get(url=image_src, timeout=5)
    content = res.content
    with open(f"{str(time.time())}.jpg", "wb") as f:
        f.write(content)

得到的第一张图片,贴到博客中记录。

Python - 10行代码集2000张美女图

优化代码

将代码重复逻辑进行提取,封装成公用函数,最终整理之后的代码如下:

import requests
import re
import time


# 请求函数
def request_get(url, ret_type="text", timeout=5, encoding="GBK"):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
    }
    res = requests.get(url=url, headers=headers, timeout=timeout)
    res.encoding = encoding
    if ret_type == "text":
        return res.text
    elif ret_type == "image":
        return res.content


# 抓取函数
def main():
    url = "http://www.netbian.com/mei/index.htm"
    text = request_get(url)
    format(text)


# 解析函数
def format(text):
    origin_text = split_str(text, '<div class="list">', '<div class="page">')
    pattern = re.compile('href="(.*?)"')
    hrefs = pattern.findall(origin_text)
    hrefs = [i for i in hrefs if i.find("desk") > 0]
    for href in hrefs:
        url = f"http://www.netbian.com{href}"
        print(f"正在下载:{url}")
        text = request_get(url)
        format_detail(text)


def split_str(text, s_html, e_html):
    start = text.find(s_html) + len(e_html)
    end = text.find(e_html)
    origin_text = text[start:end]

    return origin_text


def format_detail(text):
    origin_text = split_str(text, '<div class="pic">', '<div class="pic-down">')
    pattern = re.compile('src="(.*?)"')
    image_src = pattern.search(origin_text).group(1)
    # 保存图片
    save_image(image_src)


# 存储函数
def save_image(image_src):
    content = request_get(image_src, "image")
    with open(f"{str(time.time())}.jpg", "wb") as f:
        f.write(content)
        print("图片保存成功")


if __name__ == '__main__':
    main()

运行代码,得到下图所示运行效果。

Python - 10行代码集2000张美女图

目标 2000 张

20 张图片的爬取已经得到,下面目标 2000 张,初学阶段按照这种简单的方式抓取即可。

这一步需要改造的就是 main 函数:

# 抓取函数
def main():
    urls = [f"http://www.netbian.com/mei/index_{i}.htm" for i in range(2, 201)]
    url = "http://www.netbian.com/mei/index.htm"
    urls.insert(0, url)
    for url in urls:
        print("抓取列表页地址为:", url)
        text = request_get(url)
        format(text)

Python - 10行代码集2000张美女图

Python 相关文章推荐
用smtplib和email封装python发送邮件模块类分享
Feb 17 Python
在Python中使用sort()方法进行排序的简单教程
May 21 Python
使用Python的Flask框架来搭建第一个Web应用程序
Jun 04 Python
python smtplib模块自动收发邮件功能(一)
May 22 Python
在Python中输入一个以空格为间隔的数组方法
Nov 13 Python
pycharm配置当鼠标悬停时快速提示方法参数
Jul 31 Python
Django之使用celery和NGINX生成静态页面实现性能优化
Oct 08 Python
动态设置django的model field的默认值操作步骤
Mar 30 Python
Python发起请求提示UnicodeEncodeError错误代码解决方法
Apr 21 Python
对python中arange()和linspace()的区别说明
May 03 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
Aug 04 Python
Python xlrd/xlwt 创建excel文件及常用操作
Sep 24 Python
python办公自动化之excel的操作
May 23 #Python
python爬取豆瓣电影TOP250数据
May 23 #Python
基于Python绘制子图及子图刻度的变换等的问题
聊聊pytorch测试的时候为何要加上model.eval()
May 23 #Python
PyTorch 如何自动计算梯度
May 23 #Python
解决numpy和torch数据类型转化的问题
May 23 #Python
Python 用户输入和while循环的操作
May 23 #Python
You might like
php while循环得到循环次数
2013/10/26 PHP
使用php检测用户当前使用的浏览器是否为IE浏览器
2013/12/03 PHP
easyui的tabs update正确用法分享
2014/03/21 PHP
showModelessDialog()使用详解
2006/09/07 Javascript
Prototype ObjectRange对象学习
2009/07/19 Javascript
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
2011/05/02 Javascript
flexslider.js实现移动端轮播
2017/02/05 Javascript
Node.js websocket使用socket.io库实现实时聊天室
2017/02/20 Javascript
jQuery ajax动态生成table功能示例
2017/06/14 jQuery
删除table表格行的实例讲解
2017/09/21 Javascript
js实现rem自动匹配计算font-size的示例
2017/11/18 Javascript
babel之配置文件.babelrc入门详解
2018/02/22 Javascript
微信小程序云开发(数据库)详解
2019/05/17 Javascript
微信小程序点餐系统开发常见问题汇总
2019/08/06 Javascript
layui 表单标签的校验方法
2019/09/04 Javascript
JavaScript onclick事件使用方法详解
2020/05/15 Javascript
[02:17]DOTA2亚洲邀请赛 RAVE战队出场宣传片
2015/02/07 DOTA
[47:53]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#2COL VS Spirit
2016/03/02 DOTA
Python3.6简单操作Mysql数据库
2017/09/12 Python
Python爬虫抓取代理IP并检验可用性的实例
2018/05/07 Python
对numpy中的where方法嵌套使用详解
2018/10/31 Python
python 实现语音聊天机器人的示例代码
2018/12/02 Python
python 创建一维的0向量实例
2019/12/02 Python
TensorFlow tf.nn.conv2d实现卷积的方式
2020/01/03 Python
Python必须了解的35个关键词
2020/07/16 Python
Sublime Text3最新激活注册码分享适用2020最新版 亲测可用
2020/11/12 Python
使用CSS3设计地图上的雷达定位提示效果
2016/04/05 HTML / CSS
主键(Primary Key)约束和唯一性(UNIQUE)约束的区别
2013/05/29 面试题
总监职责范文
2013/11/09 职场文书
挂科检讨书范文
2014/02/20 职场文书
交通事故协议书
2014/04/15 职场文书
建筑安全生产责任书
2014/07/22 职场文书
检讨书怎么写?
2019/06/21 职场文书
Nginx配置SSL证书出错解决方案
2021/03/31 Servers
什么是SOLID
2022/03/24 Javascript