网页爬虫抓取百度图片(廖雪峰老师的python处理和复杂芜杂的网络框架给整崩溃了)
优采云 发布时间: 2021-09-25 04:10网页爬虫抓取百度图片(廖雪峰老师的python处理和复杂芜杂的网络框架给整崩溃了)
说些什么
其实一直对python这个语言很感兴趣,但是之前一直在做图像处理相关的事情,所以没怎么关注这种不能触及底层内存处理的语言,但是最近才真正用上通过 C++ 字符。字符串处理和复杂的网络框架崩溃了,看到大家都说python很好玩,所以趁着最近没事的时候学习了python。
昨天关注了廖雪峰老师的python教程(推荐基础教程)。看了基本的数据结构和逻辑后,我决定直接从一个实际的小项目来实践。最好的语言方式),所以就选择了一个比较简单的python爬虫项目来练习。
写爬虫最重要的就是了解我们平时访问的网页是什么。其实我们平时访问的网页源代码是一个字符串文件(当然也可以说是二进制文件)
每次我们在浏览器上输入一个网址,比如这个网址,浏览器会帮我们访问远程服务器,并根据绑定的ip地址发送请求,远程服务器会发送这个网页的源代码直接打包发送给我们的浏览器(html文件格式),然后我们的浏览器会解析这个字符串文件,比如通过div格式化和渲染网页,h1、h2 layouts 显示,继续发送请求给远程服务器为img这些资源获取图片,然后在网页上填写。
什么是爬虫
怎么说呢,爬虫,简单来说就是模拟浏览器获取一个网页的源代码。至于你用源代码做什么,没关系。
说的更复杂一点,爬虫其实就是对所有网页数据处理的综合,比如:自动抓取网页源代码,分析网页数据,获取关键数据并保存,或者自动下载需要的网页图片、音频,和视频。
那么当我们在写一个pythonm爬虫的时候,我们在写什么呢?
当我们需要爬虫的时候,一般会遇到比较复杂的数据需求。这个要求对于手工作业来说是非常复杂的。仅此要求就可以由爬虫轻松解决。
那么首先确定我们的需求,我们需要这个爬虫做什么?
比如我们认为一个教学网站的数据很有趣,但是它的格式太复杂,或者需要频繁翻页,不能通过复制粘贴轻易获取,爬虫就会起作用。
总之,我们以一个爬虫的例子来说明。
爬取百度图片ps:python版-Python 3.7.0
第一个爬虫当然不能选择太复杂的东西,涉及到很多复杂的网络规则,所以我们来爬一些网站,简单的让爬虫去爬。
比如抓取下载关键词下的某百度图片的图片数据。
1、建立需求
暂时确定以上需求,然后开始写真正的爬虫代码
2、 观察网页源码
首先打开百度图片,随意搜索一个关键词。比如这次我会用我最喜欢的*敏*感*词*角色栗山未来来测试
右键查看网页源码,可以看到每张图片的原创地址都是以一个简单的“objURL”开头,以一个小逗号结尾,如下:
基于此,我们可以确定爬虫应该如何运行。很简单——从网页源码中提取这些url并下载\(^o^)/~
3、获取网页源码
其实这一步我是不想写的,只是担心看了我博客刚学python的朋友可能会出错,所以说一下。
首先,我们需要在python中导入网络库urllib。因为我们需要用到的urlopen和read方法在我的python版本中,直接引用urllib会出错,所以一般使用这个import:import urllib.request
提取网页源代码的整个方法如下:
import urllib.request
def get_html(httpUrl):
page = urllib.request.urlopen( httpUrl )#打开网页
htmlCode = page.read( )#读取网页
return htmlCode
我们可以将这个方法打包成一个py文件,然后直接在其他py文件中导入这个方法,然后直接使用我们写的get_html方法。
然后将上面得到的二进制文件解码成普通字符串:
html_code=get_html(search_url)
html_str=html_code.decode(encoding = "utf-8")#将二进制码解码为utf-8编码,即str
4、提取图片地址
从网页的源代码中提取关键数据时,实际上是字符串匹配。如果这样估计C++累死我了,当然我也写过类似的,甚至更复杂的,真的是痛苦的回忆。
这里推荐一个比较简单的字符串搜索和匹配程序-正则表达式,也称为正则表达式。(英文:Regular Expression,在代码中常缩写为regex、regexp或RE)
当然,如何使用正则表达式我就不多说了。你可以自己搜索每个视频网站,看个大概就够了,或者直接看这里——正则表达式基础
了解正则表达式的基本逻辑就可以了。
进入正题,上面的步骤已经分析到每张图片的原创地址开头都有一个很简单的“objURL”,所以我们正则化的关键就是把“objURL”后面的地址取出来。这个很简单,我直接把写好的正则表达式拿出来:
reg=r'"objURL":"(.*?)",'
ps:字符串前的r主要是为了防止转义字符丢失导致的字符丢失
这个规律的作用如下:
匹配任何以 "objURL":" 开头并以 ", 结尾的字符串
然后简单地编译这个正则(记得导入 re 包):
import re
reg=r'"objURL":"(.*?)",'
reg_str = r'"objURL":"(.*?)",' #正则表达式
reg_compile = re.compile(reg_str)
然后使用上面编译的正则表达式解析第三步得到的字符串,如下:
pic_list = reg_compile.findall(html_str)
上面的 pic_list 是一个简单的列表
输出列表中的数据:
for pic in pic_list:
print(pic)
输出如下:
http://b-ssl.duitang.com/uploads/item/201609/02/20160902174427_4H2V8.jpeg
http://b-ssl.duitang.com/uploads/item/201607/18/20160718133442_cnmKP.jpeg
http://cdnq.duitang.com/uploads/item/201504/05/20150405H2814_VvZfS.jpeg
http://wxpic.7399.com/nqvaoZtoY6GlxJuvYKfWmZlkxaJhpc-bna-SmqKfYm/lmqN-oo5Gop3nXfWqYhdpxmoPGZHOozqx7fpyToXCcmYaMvIe0g6GuocOqdnmP1WGrsLCZoY-ub36elaeBr42tb6nSh5qApHqCrnyPq6K0emd6152Ti7Crh3ZiYHGvq5acpNpu
http://i1.hdslb.com/bfs/archive/801e00579f4b5bd2b83dcdd665dcc7819fce4470.jpg
http://wxpic.7399.com/nqvaoZtoY6GlxJuvYKfWmZlkxaJhpc-bna-SmqKfYm/lmqN-oo5Gop3nXfWqYhdpxmoPGZHOozqx7fpyToXCcmYaHv3vFrntnotGGeaRpsKp8nbqmZnCXh5-tqZOIrqOgmZDWmsNxoJ2bs4Jsqoy-fm2BznWlf82clpxiYHGvq5acpNpu
可以清楚的看到,有些地址不是图片地址。这可以说是我正则化的问题,但也无伤大雅(其实我也懒得改了)。一点判断就可以完美解决(由于所有图片地址都以g结尾,比如png、jpg、jpeg^_^)
for pic in pic_list:
if pic[len(pic)-1]=='g':
print(pic)
完美解,w(゚Д゚)w
ps:哈哈哈,这里当然是玩笑了,大家记得想好办法改正,算是小测试,毕竟真的是无害的。
5、下载图片
下载图片也很简单。正如我开头所说的,图片实际上是存在于远程服务器上的图片文件。只要服务器允许,我们可以很容易的通过GET请求得到这张图片。毕竟,浏览器也会这样做。,至于你得到的,没人管它是用来实际填网页还是给自己用。
python中下载图片的方式有很多种,如下三种
(以下代码不是我写的,不知道版本对不对,如有错误请自行百度。第一种在我的版本中没有问题):
def urllib_download(url):
from urllib.request import urlretrieve
urlretrieve(url, '1.png')
def request_download(url):
import requests
r = requests.get(url)
with open('1.png', 'wb') as f:
f.write(r.content)
def chunk_download(url):
import requests
r = requests.get(url, stream=True)
with open('1.png', 'wb') as f:
for chunk in r.iter_content(chunk_size=32):
f.write(chunk)
所以我们只需要下载上面列表中的每个图片网址。我选择了上面的第一个。这是urllib.request中存在的一个方法,定义如下:
urllib.request.urlretrieve(url, filename, reporthook, data)
参数说明:
url:外部或者本地url
filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。
然后一个简单的循环下载就可以了:
def download_pic(pic_adr,x):
urllib.request.urlretrieve(pic_adr, '%s.jpg' %x)
# './images/%s.jpg',这里也可以自己选择创建一个文件吧所有图片放进去,而不是直接放在当前目录下
x=0
for pic in pic_list:
if pic[len(pic)-1]=='g':
print(pic)
download_pic(pic,x)
x += 1
当然需要为每张图片选择一个本地名称,只需将名称增加1234即可。
这样,我们就结束了整个爬取过程。执行后效果如下:
可以看到,效果还是不错的。毕竟,只要把它放在那里,让它自己下载。还可以考虑如何翻页的效果。事实上,这很简单。我就讲实现一个变化。关键词的效果提醒大家(其实是因为我有点懒,不想写了)
6、更改搜索关键词
看百度搜索页面的网址:
观察这个网址,我们很容易发现原来最后一个关键字是关键词。复制就改了,但是复制之后就不简单了:
http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1546589116401_R&pv=&ic=0&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=0&height=0&face=0&istype=2&ie=utf-8&ctd=1546589116402%5E00_1519X723&word=%E6%A0%97%E5%B1%B1%E6%9C%AA%E6%9D%A5
为什么word变成%E6%A0%97%E5%B1%B1%E6%9C%AA%E6%9D%A5
这么一堆东西?
很简单,因为url是ASCII码,而这里我们用的是中文,只要稍微操作一下就可以转:
keyword=urllib.parse.quote(keyword)
search_url="http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1546580974349_R&pv=&ic=0&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ctd=1546580974351%5E00_1519X723&word="
search_url=search_url+keyword #加上关键字
urllib.parse.quote 是解码后的代码,在最后加上关键字就OK了。
简单,这个简单的python爬虫就完成了。.
虽然还是想自己写字符串识别,但是regular真的好用。建议多学习一些常规的骚技能。
就这样。
如需修改,请自行复制完整代码并进行更改。下载多个页面也是很简单的操作,就不多说了,还是可以加多线程,代理,动态ip。无论如何,这就是我的第一个爬虫。
完整源码(百度图片爬虫)
import urllib
import time
from urllib.request import urlretrieve
import re
import urllib.request
def get_html(httpUrl):#获取网页源码
page = urllib.request.urlopen( httpUrl )#打开网页
htmlCode = page.read( )#读取网页
return htmlCode
def get_keyword_urllist(keyword):#爬取当前关键词下的图片地址
keyword=urllib.parse.quote(keyword)
search_url="http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1546580974349_R&pv=&ic=0&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ctd=1546580974351%5E00_1519X723&word="
search_url=search_url+keyword #加上关键字
html_code=get_html(search_url)
html_str=html_code.decode(encoding = "utf-8")#将二进制码解码为utf-8编码,即str
reg_str = r'"objURL":"(.*?)",' #正则表达式
reg_compile = re.compile(reg_str)
pic_list = reg_compile.findall(html_str)
return pic_list
keyword="栗山未来"#自己修改,或者自己写个input或者一个txt自己读就完事了,甚至你写一个配置表,把爬取数量、爬取关键词、爬取图片大小都写好都可以
pic_list=get_keyword_urllist(keyword)
x=0
for pic in pic_list:
if pic[len(pic)-1]=='g':
print(pic)
name = keyword+str(x)
time.sleep(0.01)
urllib.request.urlretrieve(pic, './images/%s.jpg' %name)
x += 1
如果不行,请检查收录的模板是否正确或版本是否正确。
重点
最后运行上面的源码,应该会发现虽然可以下载,但是下载速度太慢了。解决它需要几秒钟,但如果它更慢,则可能需要十秒钟以上。
针对这种情况,我重写了上面的代码,加入了多线程处理,将爬取时间缩短到1s以内。我是直接上传到我的github上的,大家可以自己下载。
快速爬取百度图片-爬虫1.0版