Python爬取Bing壁纸并结构化保存-上

本文最后更新于:几秒前

Bing 壁纸质量一向不错,有没有办法可以批量的下载Bing上的壁纸呢?答案是有的,可以使用Python 爬虫。

Python 不但在机器学习,大数据方面有不错的表现,而且在网络请求,数据爬取方面也表现不错。

下面进入正题:

使用到的库文件:

  • Gevent:基于协程的Python 网络库

  • bs4:网页解析

  • uuid :防止文件名称重复

  • sqlite3:轻量型数据库

  • time:获取时间

以下是整个爬虫需要的库文件,如果没有对应的库文件,可以用pip 获取

1
2
3
4
5
6
import gevent 
gevent.monkey.patch_all() #[1]
from bs4 import BeautifulSoup
import uuid
import time
import sqlit3

[1] 打上猴子补丁,使得一些Python自带的阻塞式系统调用的标准库,变为协程,而且一定要在导入其他包之前打上补丁,否则会报错!!

接下来要对网页文件结构进行分析:

这是第一页的链接:
page1.jpg

这是第二页的链接:
page2.jpg

细心的可能发现了第一页与第二页的链接区别就是?p=后边的数字不同。现在我们已经知道了每页图片页面的链接。接下来我们构造请求头,构造请求头是为了使爬虫看起来像是浏览器。

1
2
3
4
5
6
7
FAKEHEADER= { 
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset': 'UTF-8,*;q=0.5',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0',
}

然后我们来分析每页图片的网页结构。

开发人员工具.png

打开浏览器的开发人员工具,我们可以看到,每张图片都是一个标签,其src属性就是图片文件的链接。

知道了网页的结构,接下来写获取图片链接的函数。

1
2
3
4
5
6
def Get_Picture(URL,FAKEHEADER,List):
r=requests.get(URL,headers=FAKEHEADER).content
soup=BeautifulSoup(r,'lxml')
img_list=soup.findAll('img')
for img in img_list:
List.append(img.get('src'))

这里传入了网页的链接,上边构造的请求头,以及一个列表,这个是将获取的图片链接放到这个列表中,以备后用。

接下来是保存图片,下边写保存图片的函数:

1
2
3
4
def Save_Picture(img_url,FAKEHEADER):
img=requests.get(img_url,headers=FAKEHEADER).content
Mapid=uuid.uuid5(uuid.NAMESPACE_URL,img_url).hex
insert_image_db(Mapid,img)

insert_imge_db() 是将要写的结构化存储图片的函数。
在完成图片下载后,我们需要对图片进行结构化保存,这里用到了sqlite数据库。

要对数据库进行操作,首先需要与数据库进行连接。

1
2
3
def get_connect():
connect=sqlite3.connect("./Picture.db")
return connect

这个函数是连接本地的Picture.db数据库,如果本地不存在这个数据库,则会创建这个数据库。

接下来我们初始化数据库,创建表结构。

1
2
3
4
5
def init():
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+"初始化数据库..")
connect=get_connect()
connect.execute("create table Picture (UUID,Image);")
connect.close()#完成操作后,要及时关闭连接

表中有两个字段,一个是图片的UUID,另一个就是图片的数据。在创建完表结构后,我们开始写插入函数。

1
2
3
4
5
6
7
8
9
10
11
def insert_image_db(Mapid,image):
connect=get_connect()
img_blob=sqlite3.Binary(image)
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+Mapid+" have saved!")
try:
connect.execute("insert into Picture (UUID,Image) values(?,?);",(Mapid,img_blob))
connect.commit()
connect.close()
except IOError:
print("IOError!")
connect.close()

在存储图片前,我们首先要将图片转换为BLOB格式,然后以图片的UUID,和图片数据为参数,执行 insert SQL语句。最后别忘了关闭连接。

到此,整个爬虫的功能函数就写完了,接下来我们要将其组装起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if __name__ == '__main__':
#首先,先构造图片页面的链接。同时建立协程任务。
index=int(input("输入页码:"))
jobs=[]
jobs1=[]
links=[]
p=pool.Pool(10)
time1=time.time()
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+"分配任务中...")
for i in range(index):
url=URL_base+"?p="+str(i+1)
jobs1.append(p.spawn(Get_Picture,url,FAKEHEADER,links))
gevent.joinall(jobs1)
#开始爬取每个页面上的图片,并保存。
init()#首选初始化数据库
for url in links:
jobs.append(p.spawn(Save_Picture,url,FAKEHEADER))
gevent.joinall(jobs)
print("共计{:d}张图片,耗时{:.2f}下载存储完毕".format(len(links),time.time()-time1))

这样,我们就把爬虫的各个功能组件组装起来了。
执行结果1.jpg
执行结果2

这是完整代码:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from gevent import pool,monkey
monkey.patch_all()
from bs4 import BeautifulSoup
import gevent
import requests
import uuid
import time
import random
import sqlite3
FAKEHEADER= {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset': 'UTF-8,*;q=0.5',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0',
}
URL_base="http://bing.ioliu.cn/"
def Get_Picture(URL,FAKEHEADER,List):
r=requests.get(URL,headers=FAKEHEADER).content
soup=BeautifulSoup(r,'lxml')
img_list=soup.findAll('img')
for img in img_list:
List.append(img.get('src'))
def Save_Picture(img_url,FAKEHEADER):
img=requests.get(img_url,headers=FAKEHEADER).content
Mapid=uuid.uuid5(uuid.NAMESPACE_URL,img_url).hex
insert_image_db(Mapid,img)
def get_connect():
connect=sqlite3.connect("./Picture.db")
return connect
def insert_image_db(Mapid,image):
connect=get_connect()
img_blob=sqlite3.Binary(image)
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+Mapid+" have saved!")
try:
connect.execute("insert into Picture (UUID,Image) values(?,?);",(Mapid,img_blob))
connect.commit()
connect.close()
except IOError:
print("IOError!")
connect.close()
def init():
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+"初始化数据库..")
connect=get_connect()
connect.execute("create table Picture (UUID,Image);")
connect.close()
if __name__ == '__main__':
index=int(input("输入页码:"))
jobs=[]
jobs1=[]
links=[]
p=pool.Pool(20)
init()
time1=time.time()
print(time.strftime('[ %H:%M:%S ]: ',time.localtime(time.time()))+"分配任务中...")
for i in range(index):
url=URL_base+"?p="+str(i+1)
jobs1.append(p.spawn(Get_Picture,url,FAKEHEADER,links))
gevent.joinall(jobs1)
for url in links:
jobs.append(p.spawn(Save_Picture,url,FAKEHEADER))
gevent.joinall(jobs)
print("共计{:d}张图片,耗时{:.2f}下载存储完毕".format(len(links),time.time()-time1))

这里另附查看数据库的代码:

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
import cv2
import sqlite3
def get_con():
con=sqlite3.connect("./Picture.db")
return con
def get_image(MapID):
sqli="select Image from Picture where UUID =:MapID";
con=get_con()
cursor=con.cursor()
param={"MapID":MapID}
cursor.execute(sqli,param)
img=cursor.fetchone()
con.close()
return img
def showimage(UUID):
img=get_image(UUID)
with open(UUID+".jpg",'wb') as f:
f.write(img[0])
cv2.imshow('IMG', cv2.imread(UUID+".jpg"))
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
while True:
UUID=input("输入UUID,X退出:")
if UUID!="x":
showimage(UUID)
else:
exit(0)

如有不足或不正确之处,请指出,谢谢!
代码仅供学习,不可用于爬取Bing壁纸


Python爬取Bing壁纸并结构化保存-上
https://blog.icansudo.top/2020/04/23/Python爬取Bing壁纸并结构化保存/
作者
odin
发布于
2020年4月23日
许可协议