先上效果图。
如搜取并下载【鬼灭之刃】和【刀剑神域】相关图片
相关过程分析:
(PS:因为刚学爬虫没几天,若大佬发现有什么问题欢迎指正)
这里爬取的网站是免费提供图片的51贴图。若光爬取单一或者连续网页的图片是很简单的,但是如果要爬取用户输入的指定类型图片呢(如上述的【刀剑神域】),这就需要先找到用户输入串和对应url之间的联系。通过尝试发现,如找【天空之城】,改字符串直接包含在网页的url中:
那么,第一步:
我们可以将用户输入的串s填入
https://www.51tietu.net/pic/{}/.format(s)
那么就这个url就是我们第一步要爬的网站。不过,由于输入的串有可能是中文,直接丢进askurl函数可能会解码失败,所以要先对读入的串s进行下面操作
s = urllib.parse.quote(s)
这样就可以正常得到网页的html。
第二步:
观察网页的页数和url的关系,如到第二页
发现后缀多了1,那么说明第一页就是/0,第二页/1 。 所以我们在爬取所有页数的时候,只需要控制循环添加url的后缀即可。即第一步部分如下图
for idx in range(0,num//18 + 6): #num是用户需要的图片数,18是一页的数,后面加6保证能找得到那么多
url_tmp = url1 + str(idx)
html1 = askurl(url_tmp)
soup1 = BeautifulSoup(html1, "html.parser")
第三步:
现在可以矛头指向图片本身了。先F12看封面图是否是我们要找的。
但是发现封面图的链接打开并不是我们要找的原图,而点开封面得到的新网页才有我们的目标图片,但是这时候网页的url似乎又变得无序了起来。
我们现在离要找的图片的链接只差了一步。就是怎么得到上图的url呢?这时候我们回到前一步,找到前面入口处的对应超链接。(把鼠标移动到标题处即可显示),如图:
观察这里:href="/p/24998501.html"
和前面那张图对比,发现就是后面那个链接https://www.51tietu.net/p/24998501.html
的后缀,前面的https://www.51tietu.net/
其实就是首页(原谅博主还没学HTML,术语上可能有问题)。那么自然想到,我们只需要爬取要找的图在此的超链接,然后相当于嵌套,变成爬取这个url的信息。那么要找的图的我们已经得到地址了。
最后一步:
最后一步就相当于最简单的爬虫了,爬取img标签下的图片链接即可。然后存入集合中(有可能爬到重复的)。最后,整理一遍思路:
1.先爬取包含s字符串(关键字)的网页
2.找到每个封面对于图片的超链接
3.再对超链接(目标图片的url)进行爬取,找到特定img标签下的链接
那么代码化的话就是一个循环控制页数,把所有超链接存入列表,后面一个循环控制对列表内的每个url进行爬取,再嵌套一个循环找到链接。
(第一次做爬虫,代码可能比较不成熟,望大佬指正)
源代码:
#-*- coding = utf-8 -*-
from bs4 import BeautifulSoup
import re
import urllib.request, urllib.error
import xlwt
import sqlite3
import requests
import os
def main():
datalist = getData()
download(datalist)
findLink = re.compile(r'href="(.*?).html"')
findImg = re.compile(r'src="(.*?)"',re.S)
findTitle = re.compile(r'<h1>(.*?)</h1>')
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
findJudge = re.compile(r'<span>(\d*)人评价</span>')
findInq = re.compile(r'<span class="inq">(.*)</span>')
flag = True
def askurl(url):
head = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36"}
request = urllib.request.Request(url,headers = head)
html = ""
try:
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8")
except urllib.error.URLError as e:
if hasattr(e,"code"):
print(e.code)
if hasattr(e,"reason"):
print(e.reason)
flag = False
return html
def getData():
datalist = []
html = ""
# num = 10
s1 = ""
s2 = ""
s3 = ""
s1 = input("输入你想查找图片的人物、角色、番剧名称或者风景等(一个词~)\n")
num = eval(input("输入你想下载的图片的数量(0->1k),建议百张以内:\n"))
print("====林肯死大头!!====\n")
word = s1
word = urllib.parse.quote(word)
data = []
url1 = "https://www.51tietu.net/pic/{}/".format(word)
cnt = 0
for idx in range(0,num//18 + 6):
url_tmp = url1 + str(idx)
html1 = askurl(url_tmp)
soup1 = BeautifulSoup(html1, "html.parser")
temp = str(soup1)
for item in soup1.find_all(target="_blank"):
item = str(item)
for j in re.findall(findLink, item):
# j = str(j)
data.append(j)
cnt += 1
print("===以查找到%d张===\n" %cnt)
if cnt>=num*3:
break
if cnt >= num*3 :
break
if cnt>=num*3:
break
cnt = 0
datalist = set(datalist)
print("~~~~~正在缓存图片下载地址,请等待~~~~")
for item in data:
item = str(item)
url = "https://www.51tietu.net{}.html".format(item)
html = askurl(url)
soup = BeautifulSoup(html,"html.parser")
for i in soup.find_all('p'):
i = str(i)
for j in re.findall(findImg,i):
if '.jpg' in str(j) :
datalist.add(str(j))
cnt += 1
if len(datalist)>=num:
break
if len(datalist) >= num :
break
if len(datalist) >= num :
break
datalist = list(datalist)
return datalist
def download(datalist):
dir = os.getcwd(); # 当前工作目录。
cnt = 1
print("··········downloading!(请等待数分钟~) ``````````````")
for item in datalist:
url = str(item)
url.replace('[','')
url.replace(']','')
url.replace('\\' ,'')
# print(url)
urllib.request.urlretrieve(url, dir + '\\result{}.jpg'.format(cnt)) # 下载图片。
print("===已下载{}张!可在根目录查看图片下载过程~===\n".format(cnt))
cnt += 1
print("下载完成,去根目录看看爬取的成果吧~")
a = input("===按任意键退出====")
main()