Python下载网络图片方法汇总与实现

Stella981
• 阅读 523

> 本文介绍下载python下载网络图片的方法,包括通过图片url直接下载、通过re/beautifulSoup解析html下载以及对动态网页的处理等。

>​本期小编推送2021初学者一定会用到的Python资料,含有小编自己呕心沥血整理的免费书籍/视频/在线文档和编辑器/源代码,关于`Python`的安装qun:850973621

### 通过pic_url单个/批量下载

已知图片url,例如http://xyz.com/series-\*(1,2..N).jpg,共N张图片,其链接形式较为固定,这样经简单循环,直接通过\`f.write(requests.get(url).content)'即可以二进制形式将图片写入。

```
import os
import requests

def download(file_path, picture_url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36             (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE",
        }
    r = requests.get(picture_url, headers=headers)
    with open(file_path, 'wb') as f:
        f.write(r.content)

def main():
    os.makedirs('./pic/', exist_ok=True)  # 输出目录

    prefix_url = 'http://xyz.com/series-'  # 同一类目下的图片url前缀
    n = 6  # 该类目下的图片总数

    tmp = prefix_url.split('/')[-1]
    for i in range(1, n + 1):
        file_path = './pic/' + tmp + str(i) + '.jpg'
        picture_url = prefix_url + str(i) + '.jpg'
        download(file_path, picture_url)

if __name__ == '__main__':
    main()
复制代码
```

### 正则re解析html获取pic_url后下载

在实际操作中,图片url按序排列情况较少,多数情况下用户仅知道网页url,需要对当前网页htnl内容进行解析,获取源码中包含的图片url,常用方法有正则表达式匹配或BeautifulSoup等库解析的方法。

正则re解析的思路是:首先通过`requests.get(url).text`获得当前页面html源码;然后通过正则表达式匹配图片url,如`re.compile(r'[a-zA-z]+://[^\s]*\.jpg')` 正则式一般会得到.jpg结尾的url,但其他网站图片url可能会以.png或.webp等结尾,甚至需要其他的正则匹配,为此,读者需要对正则表达式有所了解,强烈推荐[正则表达式30分钟入门教程](https://www.jb51.net/tools/zhengze.html);将前一步得到的图片url加入列表,进行下载。

```
import os
import re
import requests

def get_html(url):
    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 ",
        }
    html = requests.get(url, headers=headers).text

    return html

def parse_html(html_text):
    picre = re.compile(r'[a-zA-z]+://[^\s]*\.jpg')  # 本正则式得到.jpg结尾的url
    pic_list = re.findall(picre, html_text)

    return pic_list

def download(file_path, pic_url):
    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 ",
        }
    r = requests.get(pic_url, headers=headers)
    with open(file_path, 'wb') as f:
        f.write(r.content)

def main():
    # 使用时修改url即可
    url = 'http://xyz.com/series'
    html_text = get_html(url)
    pic_list = parse_html(html_text)

    os.makedirs('./pic/', exist_ok=True)  # 输出目录
    for pic_url in pic_list:
        file_name = pic_url.split('/')[-1]
        file_path = './pic/' + file_name

        download(file_path, pic_url)

if __name__ == '__main__':
    main()
复制代码
```

### 通过bs4获取pic_url

与正则匹配思路类似,只不过通过Beautiful Soup解析html获得图片url列表,然后依次下载图片。由于各网站html结构有差异,用户需要自行进行适当修改。以下代码是对豆瓣图片的下载。

```
import os
import time
import requests
from bs4 import BeautifulSoup

def get_html(url):
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36             (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    }
    html = requests.get(url, headers=headers).text

    return html

def parse_html(html_text):
    soup = BeautifulSoup(html_text, 'html.parser')
    li = soup.find_all('div', attrs={'class':'cover'})

    pic_list = []
    for link in li:
        pic_url = link.find('img').get('src')
        pic_url = pic_url.replace('/m/', '/l/')
        pic_list.append(pic_url)

    return pic_list

def download(file_path, pic_url):
    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 ",
        }
    r = requests.get(pic_url, headers=headers)
    with open(file_path, 'wb') as f:
        f.write(r.content)

def main():
    '从豆瓣下载石原里美图片,观察发现每页包含30张图片,其url按30递增,如下所示'
    pic_list = []
    for i in range(10):
        url = 'https://movie.douban.com/celebrity/1016930/photos/?type=C&start=' + str(30*i) + '&sortby=like&size=a&subtype=a'
        html_text = get_html(url)
        pic_list += parse_html(html_text)

    os.makedirs('./pic/', exist_ok=True)  # 输出目录

    for i, pic_url in enumerate(pic_list):
        if i%30 == 0:
            print('正在下载第%s页'%(i/30+1))
        file_name = pic_url.split('/')[-1].split('.')[0] + '.jpg'
        file_path = './pic/' + file_name

        download(file_path, pic_url)

if __name__ == '__main__':
    main()
复制代码
```

在下载图片时,发现可以直接访问图片的缩略图url进行下载,但由于豆瓣的反爬策略,直接访问原图url会被服务器拒绝,见下图。解决方法见下一部分。

![image.png](https://upload-images.jianshu.io/upload\_images/25205170-ac1b7f288401518d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

### 可能遇到的问题

*   网站反爬虫机制

    1.  User-Agent:模拟浏览器访问,添加后,服务器会认为是浏览器正常的请求。一般与网页操作相关访问都予以添加。
    2.  Referer:浏览器以此来判断你从哪一个网页跳转过来。例如在上述豆瓣图片的下载示例中,直接输入网址会被拒绝,但你在网站一步步点击却会在同一地址中得到内容,这就是因为你在一步步访问时是有一个前序跳转地址的,这个地址可以通过“F12”在header中得到,如果找不到的话试一试根目录地址“[movie.douban.com/”,或是前几步的地址”…](https://movie.douban.com/%E2%80%9D%EF%BC%8C%E6%88%96%E6%98%AF%E5%89%8D%E5%87%A0%E6%AD%A5%E7%9A%84%E5%9C%B0%E5%9D%80%E2%80%9Dhttps://movie.douban.com/celebrity/1016930%E2%80%9C%EF%BC%8C%E6%9C%89%E6%97%B6referer%E5%B9%B6%E4%B8%8D%E6%98%AF%E9%82%A3%E4%B9%88%E4%B8%A5%E6%A0%BC%E3%80%82%E5%85%B7%E4%BD%93%E5%AE%9E%E7%8E%B0%E4%BB%A3%E7%A0%81%E5%8F%AF%E8%A7%81%E6%88%91%E7%9A%84)\[GitHub仓库’adv\_bs4\_url.py‘文件\](https://github.com/tmylla/Pic\_download\_via\_py/blob/master/advanced/adv\_bs4\_url.py)。
    3.  ip伪装:构建ip池。
    4.  Cookie伪装:cookie是服务器用来辨别你此时的状态的,每一次向服务器请求cookie都会随之更新。
*   常用正则式匹配

    *   强烈推荐[正则表达式30分钟入门教程](https://www.jb51.net/tools/zhengze.html)
*   网页的数据采用异步加载,如js渲染的页面或ajax加载的数据通过get不到完整页面源码。

    *   一种方案是常说的动态爬虫,即采用一些第三方的工具,模拟浏览器的行为加载数据,如Selenium、PhantomJs等。网络上有较多介绍文章,有点麻烦就没有自己写了,后续有需求的话在做吧,不过其他方法已经够用了。

    *   另外可以通过分析页面,找到请求借口,加载页面。其核心就是跟踪页面的交互行为 JS 触发调度,分析出有价值、有意义的核心调用(一般都是通过 JS 发起一个 HTTP 请求),然后我们使用 Python 直接访问逆向到的链接获取价值数据。通过"F12”进行分析,例如对于花瓣网,可以获得其链接为"[huaban.com/search/?q=石…](https://huaban.com/search/?q=%E7%9F%B3%E5%8E%9F%E9%87%8C%E7%BE%8E&kbk95lmw&page=4&per\_page=20&wfl=1%E2%80%9D%EF%BC%8C%E5%A6%82%E4%B8%8B%E5%9B%BE%E6%89%80%E7%A4%BA%EF%BC%8C%E6%9B%B4%E6%94%B9%E2%80%9Cpage=\*%E2%80%9D%E5%BE%97%E5%88%B0%E5%85%B6%E4%BB%96%E9%A1%B5%E9%9D%A2%EF%BC%8C)\`request.urlopen(url).read()\`读取网页。

![image.png](https://upload-images.jianshu.io/upload\_images/25205170-040fec23652b458a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

*   其他问题...

### Pyautogui,鼠标模拟点击的“傻瓜式”流程

本方法仅适用于重复性的工作,而且效率较低,但完全没有被反爬虫策略屏蔽的风险。其核心思想与word中的“宏”类似,就是你告诉计算机一次循环中鼠标分别如何操作,然后让其自动循环。代码简单明了。

```
import pyautogui
import time

pyautogui.FAILSAFE = True

def get_mouse_positon():
    time.sleep(3)  # 此间将鼠标移动到初始位置
    x1, y1 = pyautogui.position()
    print(x1, y1)
    pyautogui.click(x=x1, y=y1, button='right')  # 模拟鼠标右键点击,呼出菜单
    time.sleep(5)  # 此间将鼠标移动到“save image as...”选项中央
    x2, y2 = pyautogui.position()
    print(x2, y2)
    pyautogui.click(x=x2, y=y2)  # 模拟鼠标左键点击,点中“save image as...”
    time.sleep(10)  # 此间弹出保存文件弹窗,自行选择保存位置,并将鼠标移至“保存(S)”按钮中央
    x3, y3 = pyautogui.position()
    pyautogui.click(x=x3, y=y3)
    print(x3, y3)

def click_download(N):
    for i in range(N):  # 拟下载图片数量
        pyautogui.click(x=517, y=557, duration=0.25, button='right')  # 呼出菜单,自行将x/y设置为x1/y1
        time.sleep(1)
        pyautogui.click(x=664, y=773, duration=0.25)  # 下载,x/y为x2/y2
        time.sleep(1)
        pyautogui.click(x=745, y=559, duration=0.25)  # 保存,x/y为x3/y3
        time.sleep(1)
        pyautogui.click(x=517, y=557, duration=0.25)  # 进入下一张图片
        time.sleep(2) # 取决于网络加载速度,自行设置

if __name__ == "__main__":
    # get_mouse_positon()  # 一开始只运行此命令,获取屏幕坐标,后续注释掉该句
    click_download(10)
复制代码
```

原文链接:https://juejin.cn/post/6844904194726428685

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这