本人python小白一个,为了入门,决定还是直接上个小项目-->爬虫。废话不多说,先剖析一下必应的响应页面。打开firefox,到必应里搜索关键词“欧阳娜娜”,再查看请求头发现是这样的:
这里url中对汉字进行了转码,类似encodeURL的处理,python中可以做如下处理:
import urllib
key="欧阳娜娜"
new = new = urllib.parse.quote(key)
这样,我们就可以自定义关键词了,想爬什么图片就爬什么图片。下一步就是确定url中的参数,为了程序中使用统一的url,我对网页进行多次请求,得到多个url然后找出哪些参数是我们需要关心的,方法是就是简单的滚动窗口,看到下一页就点击下一页,这个过程中需要记录下url及参数设置,方便分析
最终确定了下面的url。确定了url之后,就可以得到一页包含count数的图片了,但是这些图片都还只是缩略图,而我们的目标是原图,就是bing从哪里找来的,我们就去哪里找。
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2107.204 Safari/537.36'
}
url = "https://cn.bing.com/images/async?q={0}&first={1}&count={2}&scenario=ImageBasicHover&datsrc=N_I&layout=ColumnBased&mmasync=1&dgState=c*9_y*2226s2180s2072s2043s2292s2295s2079s2203s2094_i*71_w*198&IG=0D6AD6CBAF43430EA716510A4754C951&SFX={3}&iid=images.5599"
接下来就是找到真正的原图所在地。打开浏览器,查看源代码,发现这里有好多url,而图片的onclick方法传递的是href,观察发现href也不是我们最终的目标,因为:虽然我们能通过https://cn.bing.com+href得到一个url但是这个也是bing加载原图之后创建的一个UI,为了用户体验而已,但我们是机器呀,我们是不需要UI的(狗头保命)
为了保险起见,我们到这个UI里找找原图的踪迹,果然功夫不负有心人,murl的值就是原图的url!
接下来就是写代码准备开工了!先定义全局变量如下
import sys
import os
import urllib
from bs4 import BeautifulSoup
import re
import time
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2107.204 Safari/537.36'
}
url = "https://cn.bing.com/images/async?q={0}&first={1}&count={2}&scenario=ImageBasicHover&datsrc=N_I&layout=ColumnBased&mmasync=1&dgState=c*9_y*2226s2180s2072s2043s2292s2295s2079s2203s2094_i*71_w*198&IG=0D6AD6CBAF43430EA716510A4754C951&SFX={3}&iid=images.5599"
#需要爬取的图片关键词
name="欧阳娜娜"
#本地存储路径
path = "D:\\"+name
然后是获取列表页
'''获取缩略图列表页'''
def getStartHtml(url,key,first,loadNum,sfx):
page = urllib.request.Request(url.format(key,first,loadNum,sfx),headers = header)
html = urllib.request.urlopen(page)
return html
然后获取这一页的原图url并统计个数。需要注意的是,由于html文本的原因,被浏览器解析时& = &这是html里所涉及到的一点点东西,在处理页面时我们需要注意。
'''从缩略图列表页中找到原图的url,并返回这一页的图片数量'''
def findImgUrlFromHtml(html,rule,url,key,first,loadNum,sfx,count):
soup = BeautifulSoup(html,"lxml")
link_list = soup.find_all("a", class_="iusc")
url = []
for link in link_list:
result = re.search(rule, str(link))
#将字符串"amp;"删除
url = result.group(0)
#组装完整url
url = url[8:len(url)]
#打开高清图片网址
getImage(url,count)
count+=1
#完成一页,继续加载下一页
return count
再将图片存下来
'''从原图url中将原图保存到本地'''
def getImage(url,count):
try:
time.sleep(0.5)
urllib.request.urlretrieve(url,path+'\\'+str(count+1)+'.jpg')
except Exception :
time.sleep(1)
print("产生了一点点错误,跳过...")
else:
print("图片+1,成功保存 " + str(count+1) + " 张图")
最后是main函数。因为没有找到bing是怎样对资源加载完毕后用户仍然在请求做处理,暂时还没有找到停止扒图的方法,于是我只给它限制了一个数,只扒取这么多,如果有人知道怎么判断停止欢迎给我留言哟,嘻嘻嘻!
def main():
key = urllib.parse.quote(name)
first = 1
loadNum = 35
sfx = 1
count = 0
#正则表达式
rule = re.compile(r"\"murl\"\:\"http\S[^\"]+")
#图片保存路径
if not os.path.exists(path):
os.makedirs(path)
#目前还没有找到停止的办法,还请知道的朋友告知
while count<500:
html = getStartHtml(url,key,first,loadNum,sfx)
count = findImgUrlFromHtml(html,rule,url,key,first,loadNum,sfx,count)
first = count+1
sfx += 1
if __name__ == '__main__':
main()
最后再来一张成果展示吧
最后再来完整的代码吧
import sys
import os
import urllib
from bs4 import BeautifulSoup
import re
import time
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2107.204 Safari/537.36'
}
url = "https://cn.bing.com/images/async?q={0}&first={1}&count={2}&scenario=ImageBasicHover&datsrc=N_I&layout=ColumnBased&mmasync=1&dgState=c*9_y*2226s2180s2072s2043s2292s2295s2079s2203s2094_i*71_w*198&IG=0D6AD6CBAF43430EA716510A4754C951&SFX={3}&iid=images.5599"
#需要爬取的图片关键词
name="欧阳娜娜"
#本地存储路径
path = "D:\\"+name
'''获取缩略图列表页'''
def getStartHtml(url,key,first,loadNum,sfx):
page = urllib.request.Request(url.format(key,first,loadNum,sfx),headers = header)
html = urllib.request.urlopen(page)
return html
'''从缩略图列表页中找到原图的url,并返回这一页的图片数量'''
def findImgUrlFromHtml(html,rule,url,key,first,loadNum,sfx,count):
soup = BeautifulSoup(html,"lxml")
link_list = soup.find_all("a", class_="iusc")
url = []
for link in link_list:
result = re.search(rule, str(link))
#将字符串"amp;"删除
url = result.group(0)
#组装完整url
url = url[8:len(url)]
#打开高清图片网址
getImage(url,count)
count+=1
#完成一页,继续加载下一页
return count
'''从原图url中将原图保存到本地'''
def getImage(url,count):
try:
time.sleep(0.5)
urllib.request.urlretrieve(url,path+'\\'+str(count+1)+'.jpg')
except Exception :
time.sleep(1)
print("产生了一点点错误,跳过...")
else:
print("图片+1,成功保存 " + str(count+1) + " 张图")
def main():
key = urllib.parse.quote(name)
first = 1
loadNum = 35
sfx = 1
count = 0
#正则表达式
rule = re.compile(r"\"murl\"\:\"http\S[^\"]+")
#图片保存路径
if not os.path.exists(path):
os.makedirs(path)
#抓500张好了
while count<500:
html = getStartHtml(url,key,first,loadNum,sfx)
count += findImgUrlFromHtml(html,rule,url,key,first,loadNum,sfx,count)
first = count+1
sfx += 1
if __name__ == '__main__':
main()
songyahui0418: 牛啊,亲测代码可以跑起来 20241010
努力努力再努力wwh: [code=python] 停止的代码:findImgUrlFromHtml方法里有个bug return count #完成一页,继续加载下一页 # return count [/code]
「已注销」: 抛出错误 [code=python] url = result.group(0) AttributeError: 'NoneType' object has no attribute 'group' [/code] 如何处理
「已注销」: 抛出错误 [code=python] url = result.group(0) AttributeError: 'NoneType' object has no attribute 'group' [/code] 如何处理
LexieKeepsCool: 非常好用,感谢!但是还是遇到一些网络导致的程序卡死问题,所以要改参数重新开始爬。想问博主sfx和first的参数是什么意思呢?sfx一定需要和first有匹配关系吗?