0%

python下载图片与视频

python基础知识准备

浏览器请求头header

为了使服务器检测到它支持的浏览器标识,以便获得服务器的响应,需要在程序中加入浏览器请求头header,不然服务器会拒绝程序访问。
方法:打开网页–>右键检查–>在network中找到以下信息,复制粘贴到程序中。

1
header = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'

正则表达式

使用正则表达式匹配出网页里的图片。常用的正则有:
.*?匹配不需要的内容,选取的内容加括号(.*?)。例:(.*?)(.*?\.html)(.*?\.jpg)
?匹配最短内容;
|的用法:[src|file]匹配src或file、(.*?\.(?:jpg|JPG|jpeg|JPEG|gif|GIF|png|PNG))匹配多种图片格式;
匹配数字字母[A-Za-z0-9]
提取数字.*?(\d+).*?
注意:如果链接中有?\,加\转义,改成\?\\([]表示,[(]
下载网站图片或获取html时会用到如下正则表达式,照此修改。

1
2
3
4
5
reg = r'src="(.*?\.jpg)" /></a></p>'
reg = r'[src|file]="(.*?\.(?:jpg|gif))" onload="'
reg = r'v2-(.*?\.(?:jpg|gif)).*?noscript>?'
reg = r'href="(.*?\.html)"><img width="234"'
reg = r'<li><a>.*?(\d+).*?: </a></li><li id='

利用re.findall找到html页面中的所有图片地址或新的链接地址:

1
2
allimage = re.findall(reg, html.decode('utf-8', errors='ignore'))
allhtml = re.findall(reg, html.decode('utf-8', errors='ignore'))

异常处理

程序使用了循环,在不断访问服务器和下载图片时可能会发生异常,我们需要捕获处理它,否则程序会终止。try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句,程序不会停止。以下为简单的try…except…else的语法:

1
2
3
4
5
6
7
8
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生

在except里可以保存错误内容至某个文件,方便查看错误内容。

1
2
with open('wrong_url.txt','a') as f:
f.write('\n'.join(url))

切片

有时候需要对某些网址做一些切片和合并处理。
num_str = "0123456789"

正序切片:

截取从 2 ~ 5位置的字符串print(num_str[2:6])
截取从 2 ~ 末尾的字符串print(num_str[2:])
截取从开始 ~ 5位置的字符串print(num_str[:6])
截取完整的字符串print(num_str[:])
从开始位置,每隔一个字符截取字符串print(num_str[::2])
从索引 1 开始,每隔一个取一个print(num_str[1::2])

倒序切片:

-1表示倒数第一个字符print(num_str[-1])
截取从 2 ~ 末尾-1的字符串print(num_str[2:-1])
截取字符串末尾两个字符print(num_str[-2:])
字符串的逆序print(num_str[::-1])

1
2
3
4
string = list[0:8]
url = '' + string + '&' + list[13:]
url_new = url[:-5:]
url_short = int(url[-11:-5:])#强制转换成int类型

下载单个页面的图片

下载单个页面的图片程序很简单,一般不需要使用函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import urllib.request
import re
def Header():
header = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'
opener = urllib.request.build_opener()
opener.addheaders = [('User-Agent', header)]
urllib.request.install_opener(opener)

reg = r'v2-(.*?\.(?:jpg|gif)).*?noscript>?'
reg = re.compile(reg)#可以省略这一行
#下载知乎某网页的图片
url = 'https://www.zhihu.com/question/' + str(num)
print(url, end=' *** ')
Header()

html = urllib.request.urlopen(url).read() #获取html
imglist = re.findall(reg, html.decode('utf-8', errors='ignore')) #从html里获取所有的图片地址。注意添加decode('utf-8', errors='ignore')
#print(imglist)#打印html里的所有图片地址
n = 0#用来计数或命名
for imgurl in imglist:#建议在循环内使用try,防止异常导致退出循环。
img = 'https://pic1.zhimg.com/v2-' + imgurl
urllib.request.urlretrieve(img, "C:/file/%s.jpg" % n)#保存图片到本地,也可以用imurl来命名
n += 1
print(n, end='-')#每下载一张图片打印一次

下载多个页面的图片

多个页面就需要用到for循环和try。程序运行过程中可能会出现异常,使用try防止退出循环。程序的主要部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for i in range(num1, num2):
try:
url = '' + str(i) + '.html'#可能的网址式样
print(url, end=' *** ')
Header()#调用函数
html = urllib.request.urlopen(url).read()
reg = r'file="(.*?\.jpg)"?'

allimg = re.findall(reg, html.decode('utf-8', errors='ignore'))
n = 0
for img in allimg:
urllib.request.urlretrieve(img, "%s-%s.jpg" % (i, n))
print(n, end="-")
n += 1
print(n)
except:
print('----------')

获取页面内的html链接

有些页面只显示了组图中的封面,点开封面图片后在新网页里才能查看所有图片,这就需要在网页里找到所有组图所在新网页的链接。建议使用自定义函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
reg1 = r'href="(.*?\.html)'   #html里找到所有组图的链接url
reg2 = r'<li><a>.*?(\d+).*?:'
reg3 = r'src="(.*?\.jpg)"'

def GetHtml(url):#获取html
print(url, end=' ******\n')
Header()
html = urllib.request.urlopen(url).read()
return html


def GetImgUrl(html):#在html里找到所有组图的链接url
allurl = re.findall(reg1, html.decode('utf-8', errors='ignore'))
for url in allurl:
html = GetHtml(url)#获取组图所在网页的html
GetImage(html, url)#获取组图中所有图片并下载


def SaveImg(html, reg, name_1, name_2):#以正则reg的方式获取html里的所有图片并下载
allimg = re.findall(reg, html.decode('utf-8', errors='ignore'))
for img in allimg:
urllib.request.urlretrieve(img, "%s-%s.jpg" % (name_1, name_2))


def GetImage(html, url):#主要函数,下载图片
#do something for url
for i in range(num1, num2):
url_n = ''
try:
html = urllib.request.urlopen(url_n).read()
SaveImg(html, reg3, url, i)#以正则reg的方式获取html里的所有图片并下载
print(x, end="-")
except:
print('----- %s -' % url)
print("")


for i in range(num1, num2):
url = '%s.html' % i
html = GetHtml(url)
GetImgUrl(html)

下载微博图片

python模拟登录

复制cookie

cookie保存在发起请求的客户端中,服务器利用cookie来区分不同的客户端。因为http是一种无状态的连接,当服务器一下子收到好几个请求时,是无法判断出哪些请求是同一个客户端发起的。而“访问登录后才能看到的页面”这一行为,恰恰需要客户端向服务器证明:“我是刚才登录过的那个客户端”。于是就需要cookie来标识客户端的身份,以存储它的信息(如登录状态)。这也意味着,只要得到了别的客户端的cookie,我们就可以假冒成它来和服务器对话。这给我们的程序带来了可乘之机。
先用浏览器登录微博,打开开发者工具,转到network。在左边的Name一栏找到当前的网址,选择右边的Headers,查看Request Headers,这里包含了该网站颁发给浏览器的cookie。复制到程序里,程序携带该cookie向网站发送请求,就能让程序假扮成刚才登录的浏览器,得到只有登录后才能看到的页面。
注意,最好是在运行程序前登录。如果过早登录,或是关闭浏览器,很可能复制的cookie就失效了。

查看图片链接

进入所要下载用户的界面–>相册–>相册专辑–>微博配图–>打开某张图片,查看网址,网址里的数字分别表示用户id、图片id和所在相册id–>查看网页源代码,选择自动换行,找到album_photo_ids,下面就是图片的id–>只复制数字和逗号到txt文件里,不要复制括号。这些图片都能下载,最多下载2000张,没有显示id的图片不知道怎么下载。

完整程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import urllib.request
import re
import sys
import io

header = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
reg = r'src="(.*?\.(?:jpg|gif))" onload="?' #通过正则获取图片
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')#改变标准输出的默认编码
cookie = r''#粘贴浏览器登录后得到的cookie,也就是从网页复制的字符串。

def PhotoNum(): #计算图片id总数
with open('photo.txt', 'r') as f: #打开储存photo_id的文件
photoid = f.read().split(',')#图片的数字代码都是用逗号隔开的,读取每一个代码
i = 0
for line in photoid:
i += 1
return i


def get_photo(User_id, Album_id):
with open('photo.txt', 'r') as f:
photoid = f.read().split(',')
i = 0
for Photo_id in photoid:
url = 'https://photo.weibo.com/%s/wbphotos/large/photo_id/%s/album_id/%s' % (
User_id, Photo_id, Album_id)#获取的是高清图片
print(url, end=' ****** ')
try:
req = urllib.request.Request(url)
req.add_header('cookie', cookie) #设置cookie
req.add_header('User-Agent', header) #设置请求头

html = urllib.request.urlopen(req).read()#获取图片的html
allimg = re.findall(reg, html.decode('utf-8', errors='ignore'))#找到html里 图片,只有一张图,格式有jpg和gif,但是都保存为jpg格式。
for img in allimg:
urllib.request.urlretrieve(img, "C:/%s.jpg" % i)
i += 1
print(i)

if (i > photonum):#大于图片总数就停止程序
return None
except:
print(url, end=' ------ ')#打印因为异常而未下载的图片的地址


photonum = PhotoNum()
print(photonum) #图片id总数
userid = ''#用户id
albumid = ''#所要下载的相册的id
get_photo(userid, albumid)

如果出现下载卡在某处,关闭程序,做好标记,从txt文件里删除已下载图片的id。重新命名接下来要下载的图片,不然会覆盖,从未下载的图片继续开始。

下载微博视频

安装you-get

使用you-get下载视频,安装方法:pip install you-get。使用方法:
you-get url默认下载到当前目录。
you-get -o dir -O name url下载到指定文件夹,并命名。
you-get -i url查看视频的清晰度,默认下载第一个。要下载的视频样式,比如高清是--format=mp4sd,使用命令:you-get --format=mp4sd url
Ctrl + c停止下载。

下载视频

进入用户主页–>相册–>视频,此时页面网址是https://weibo.com/p/%s/photos?type=video#place其中%s是用户的id,复制id,程序会用到。右键–>查看网页源代码,其中https:\/\/video.weibo.com\/show?fid=1034:id就是视频网址。只能查看到用户的前几十个视频id,所以如果视频很多,不能全部下载。视频网址是https://weibo.com/tv/show/1034:%s'%s是视频的id,程序会使用正则表达式获取所有视频id.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import urllib.request
import re
import sys
import io
import os

header = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
#改变标准输出的默认编码
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
#登录微博-->右键检查-->network-->headers-->request headers-->cookie复制
cookie = r'' #粘贴至此处


def get_videos(User_id):
url = 'https://weibo.com/p/%s/photos?type=video#place' % User_id
print(url, end=' ****** ')

req = urllib.request.Request(url)
req.add_header('cookie', cookie) #设置cookie
req.add_header('User-Agent', header) #设置请求头

html = urllib.request.urlopen(req).read()
reg = r'fid=1034:(.*?)\\"><?' #使用正则表达式获取所有视频id \\表示转义后的\
allvideos = re.findall(reg, html.decode('utf-8', errors='ignore'))

for video in set(allvideos):#集合里没有重复元素,使用set去除重复元素,不然会重复下载。
url = 'https://weibo.com/tv/show/1034:%s' % video
print(url)
cmd = 'you-get ' + url #默认下载到当前文件夹,可以指定文件夹
os.system(cmd)


userid = '' #用户id
get_videos(userid)