先上效果图。
如搜取并下载【鬼灭之刃】和【刀剑神域】相关图片
相关过程分析:
(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 osdef 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 = Truedef 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 = Falsereturn htmldef getData():datalist = []html = ""# num = 10s1 = ""s2 = ""s3 = ""s1 = input("输入你想查找图片的人物、角色、番剧名称或者风景等(一个词~)\n")num = eval(input("输入你想下载的图片的数量(0->1k),建议百张以内:\n"))print("====林肯死大头!!====\n")word = s1word = urllib.parse.quote(word)data = []url1 = "https://www.51tietu.net/pic/{}/".format(word)cnt = 0for 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 += 1print("===以查找到%d张===\n" %cnt)if cnt>=num*3:breakif cnt >= num*3 :breakif cnt>=num*3:breakcnt = 0datalist = 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 += 1if len(datalist)>=num:breakif len(datalist) >= num :breakif len(datalist) >= num :breakdatalist = list(datalist)return datalistdef download(datalist):dir = os.getcwd(); # 当前工作目录。cnt = 1print("··········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 += 1print("下载完成,去根目录看看爬取的成果吧~")a = input("===按任意键退出====")main()