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 相关文章推荐
Python遍历zip文件输出名称时出现乱码问题的解决方法
Apr 08 Python
深入源码解析Python中的对象与类型
Dec 11 Python
Python中操作mysql的pymysql模块详解
Sep 13 Python
Python实现完整的事务操作示例
Jun 20 Python
python中关于for循环的碎碎念
Jun 30 Python
Centos部署django服务nginx+uwsgi的方法
Jan 02 Python
pandas dataframe添加表格框线输出的方法
Feb 08 Python
pandas factorize实现将字符串特征转化为数字特征
Dec 19 Python
python列表推导和生成器表达式知识点总结
Jan 10 Python
python 实现汉诺塔游戏
Nov 28 Python
如何用用Python将地址标记在地图上
Feb 07 Python
Python内置数据类型中的集合详解
Mar 18 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
2020显卡排行榜天梯图 显卡天梯图2020年3月最新版
2020/04/02 数码科技
PHP反射原理与用法深入分析
2019/09/28 PHP
javascript中的有名函数和无名函数
2007/10/17 Javascript
JSON语法五大要素图文介绍
2012/12/04 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
2013/12/22 Javascript
在javascript中实现函数数组的方法
2013/12/25 Javascript
javascript封装 Cookie 应用接口
2015/08/07 Javascript
jQuery实现响应鼠标背景变化的动态菜单效果代码
2015/08/27 Javascript
jquery验证手机号是否正确实例讲解
2015/11/17 Javascript
jQuery解析json数据实例分析
2015/11/24 Javascript
jQuery插件实现多级联动菜单效果
2015/12/01 Javascript
详解Vue2+Echarts实现多种图表数据可视化Dashboard(附源码)
2017/03/21 Javascript
基于AngularJS实现的工资计算器实例
2017/06/16 Javascript
AngularJS解决ng-if中的ng-model值无效的问题
2017/06/21 Javascript
JavaScript实现的DOM树遍历方法详解【二叉DOM树、多叉DOM树】
2018/05/07 Javascript
javascript使用正则实现去掉字符串前面的所有0
2018/07/23 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
three.js 制作动态二维码的示例代码
2020/07/31 Javascript
[01:05:24]Ti4 冒泡赛第二天 iG vs NEWBEE 3
2014/07/15 DOTA
python赋值操作方法分享
2013/03/23 Python
python 字典 按key值大小 倒序取值的实例
2018/07/06 Python
Python制作动态字符图的实例
2019/01/27 Python
使用python进行波形及频谱绘制的方法
2019/06/17 Python
django ListView的使用 ListView中获取url中的参数值方式
2020/03/27 Python
Python下划线5种含义代码实例解析
2020/07/10 Python
Bench加拿大官方网站:英国城市服装品牌
2017/11/03 全球购物
介绍一下except的用法和作用
2015/01/22 面试题
普通大学毕业生自荐信范文
2014/02/23 职场文书
校长四风对照检查材料
2014/09/27 职场文书
临床医学生职业规划书范文
2014/10/25 职场文书
政风行风整改报告
2014/11/06 职场文书
售后前台接待岗位职责
2015/04/03 职场文书
母亲去世追悼词
2015/06/23 职场文书
解除处分决定书
2015/06/25 职场文书
员工给公司的建议书
2019/06/24 职场文书
JavaCV实现照片马赛克效果
2022/01/22 Java/Android