Python3利用BeautifulSoup4批量抓取站点图片的代码
边学边写代码,记录下来。这段代码用于批量抓取主站下所有子网页中符合特定尺寸要求的的图片文件,支持中断。
原理很简单:使用BeautifulSoup4分析网页,获取网页<a/>和<img/>元素,对<a/>集合反复弹栈入栈,对<img/>集合进行筛选下载。
具体代码如下:import os
import sys
import time
import urllib.request
from urllib.parse import urljoin,urlparse
from bs4 import BeautifulSoup
from threading import Thread '''
class Download(Thread): #多线程下载代码1. 为每一个图片分配一个下载线程
def __init__(self,url,filepath):
Thread.__init__(self)
self.url = url
self.filepath = filepath def run(self):
length = 0
try:
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent','Mozilla/5.0')]
urlhandle = opener.open(self.url,timeout = 30)
urlhead = urlhandle.info()
if 'Content-Length' in urlhead:
length = int(urlhead['Content-Length'])
data = urlhandle.read(10*1024)
while data:
with open(self.filepath,'ab+') as wf:
wf.write(data)
data = urlhandle.read(10*1024)
except Exception as ex:
print(self.url | '\n' + '× ' + str(ex))
try:
os.remove(self.filepath)
with open('/home/maple/Desktop/bad','a') as badFile: #超时未能完成下载则删除文件并将图片url记录到未下载链接列表中
badFile.write(self.url+'\n')
except:
pass
''' def maple(root):
tasks = [] #多线程集合
urls = [root] #待分析的网页链接
urld = [] #已分析并完成图片下载的网页链接
if os.path.exists('tmpUrls'): #读取本地待分析和已分析网页链接数据
with open('tmpUrls','r') as urlsFile:
urls = urlsFile.readlines()
for url in urls:
if url[0] == '' or url[0] == ' ':
urls.remove(url)
urls = [line[:-1] for line in urls]
if os.path.exists('tmpUrld'):
with open('tmpUrld','r') as urldFile:
urld = urldFile.readlines()
for url in urld:
if url[0] == '' or url[0] == ' ':
urld.remove(url)
urld = [line[:-1] for line in urld] try:
times =3 #设置网页读取失败后重试的次数
while urls:
curl = urls.pop()
urld.append(curl)
print('=================== Current Page: '+curl+' =======================')
try:
response = urllib.request.urlopen(curl,timeout = 5)
html = response.read()
data = html.decode('utf8')
soup = BeautifulSoup(data) #使用BeautifulSoup获取网页元素集
except Exception as ex: #读取网页失败,重试
print(ex)
if times > 0:
urls.append(curl)
urld.remove(curl)
times -= 1
else:
if curl in urld:
urld.remove(curl)
times = 3
continue
path = '/home/maple/Desktop/images/' count = 1
for list in soup.find_all('img'): #获取网页中所有图片链接
width = 0
height = 0
dict = list.attrs
if "src" in dict:
image = dict['src']
img = image[image.rfind('.'):]
if "alt" in dict: #该站点图片链接中提供的图片名属性,不同站点给出的属性可能不同甚至不一定给出图片名属性
fname = dict['alt']
filepath=os.path.join(path,fname+img)
else:
filepath = os.path.join(path,str(count)+img)
count +=1
if "width" in dict: #获取站点图片链接中提供的图片尺寸属性,width和height属性不一定给出
width = int(dict['width'])
if "height" in dict:
height = int(dict['height'])
num=1
while os.path.exists(filepath): #如获取的图片名与本地图片重名则自动按序重命名
fname,fext=os.path.splitext(filepath)
if '('+str(num-1)+')'+fext in filepath:
filepath = filepath.replace('('+str(num-1)+')'+fext,'('+str(num)+')'+fext)
else:
fname += '('+str(num)+')'
filepath = fname+fext
num +=1
for i in range(0,3): #图片下载失败后重试(如使用多线程部分的代码则无此循环)
try:
if (width == 0 or width >= 250) or (height ==0 or height >= 350):
length = 0
image_handle = urllib.request.urlopen(dict['src'],timeout = 5+i*10) #每次重试的超时时间依次递增
image_head = image_handle.info()
if 'Content-Length' in image_head: #获取图片实际大小
length = int(image_head['Content-Length'])
print(dict['src']+' ==== SIZE:{}*{} -- {}KB'.format(width,height,length/1000))
if length > 20*1000: #只下载超过一定大小的图片,避免下载网页中的图标或者链接图
with open(filepath, 'wb') as file:
image_data = image_handle.read()
file.write(image_data)
print('√')
break
'''
task = Download(dict['src'],filepath) #多线程下载代码2.为图片资源分配下载线程
task.setDaemon( True ) #将线程置为后台线程
task.start()
tasks.append(task) #启动线程并将线程加入线程集合中
'''
except Exception as ex:
if i < 2:
continue
else: #重试3次后依然下载失败则将图片url记录到未下载列表中
print('× '+str(ex))
try:
os.remove(filepath)
with open('/home/maple/Desktop/bad','a') as badFile:
badFile.write(dict['src']+'\n')
except:
pass
continue
'''
if len(tasks) >= 10:
while len([task for task in tasks if task.isAlive()]):
time.sleep(2)
tasks = []
''' for a in soup.find_all('a'): #获取当前页面中所有的链接地址,未分析的网页链接入栈
dict = a.attrs
if 'href' in dict:
url = dict['href']
if urlparse(url)[1]:
if urlparse(url)[1] == urlparse(curl)[1]:
pass
else:
url = urljoin(curl,url)
if url not in urls and url not in urld:
urls.append(url) except KeyboardInterrupt as kbi: #键盘终端,按下<C-c>终止程序,将已分析和未分析链接地址记录到本地
with open('tmpUrls','w') as urlsFile:
tmpList = [line + '\n' for line in urls]
urlsFile.writelines(tmpList)
with open('tmpUrld','w') as urldFile:
tmpList = [line + '\n' for line in urld]
urldFile.writelines(tmpList)
if __name__ == '__main__':
print("""
+++++++++++++++++++++++
version: python3.4
+++++++++++++++++=++++
""")
url = 'http://www.msnzx.com/' #示例站点(子页和图片太多,运行完成需要很长时间)
maple(url)
这段代码某些细节部分是专门针对 http://www.msnzx.com/ 这个站点的,下载其他站点数据仅需要微调一下就行了。其中分析网页直接使用了强大的第三方模块BeautifulSoup4,方便快捷。下载图片部分的实方式实在太多,上述代码中包含了2种下载方式:
1、直接使用url.request读写流一次性下载,下载任意文件时程序都是阻塞的。这种方式适合下载size较小的图片。图片要么完全下载,要么完全不下载(得到的本地文件size = 0),网络条件不佳的时候可以捕获超时异常记录未成功下载的图片url。
2、以多线程的方式下载,为每个图片资源分配一个下载线程。上述程序的注释部分即是多线程下载代码。这种方式下载迅速,就算网络不佳,也能下载到图片的部分内容。
另外还有很多下载方式,如单独调用其他模块(如urllib.request中的urlretrieve,之前文章中实现的文件多线程下载模块download)或者系统工具如wget,curl等。这种直接调用的方式能够为每一个图片分配多线程进行下载。实现方式也最简单。
Python3利用BeautifulSoup4批量抓取站点图片的代码的更多相关文章
- 使用python来批量抓取网站图片
今天"无意"看美女无意溜达到一个网站,发现妹子多多,但是可恨一个page只显示一张或两张图片,家里WiFi也难用,于是发挥"程序猿"的本色,写个小脚本,把图片扒 ...
- Hibernate学习---第十一节:Hibernate之数据抓取策略&批量抓取
1.hibernate 也可以通过标准的 SQL 进行查询 (1).将SQL查询写在 java 代码中 /** * 查询所有 */ @Test public void testQuery(){ // ...
- Python3简单爬虫抓取网页图片
现在网上有很多python2写的爬虫抓取网页图片的实例,但不适用新手(新手都使用python3环境,不兼容python2), 所以我用Python3的语法写了一个简单抓取网页图片的实例,希望能够帮助到 ...
- 使用IDM批量抓取音效素材下载
IDM下载器的站点抓取功能,能够抓取网站上的图片.音频.视频.PDF.压缩包等等文件.更重要的是,能够实现批量抓取操作,省时省力.今天就来看一下,如何用IDM巧妙的批量抓取音效素材. 1.进入音效合辑 ...
- 抓取网页图片的脚本(javascript)
抓取网页图片的脚本(javascript) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24172223 脚本内容 (没有换行) ...
- PHP抓取远程图片教程(包含不带后缀图片)
之前做微信登录开发时候,发现微信头像图片没有后缀名,传统的图片抓取方式不奏效,需要特殊的抓取处理.所以,后来将各种情况结合起来,封装成一个类,分享出来. 创建项目 作为演示,我们在www根目录创建项目 ...
- php远程抓取网站图片并保存
以前看到网上别人说写程序抓取网页图片的,感觉挺神奇,心想什么时候我自己也写一个抓取图片的方法! 刚好这两天没什么事,就参考了网上一个php抓取图片代码,重点借鉴了 匹配img标签和其src属性正则的写 ...
- 百度UEditor编辑器关闭抓取远程图片功能(默认开启)
这个坑娘的功能,开始时居然不知道如何触发,以为有个按钮,点击一下触发,翻阅了文档,没有发现,然后再网络上看到原来是复制粘贴非白名单内的图片到编辑框时触发,坑娘啊............... 问题又来 ...
- 使用HtmlAgilityPack批量抓取网页数据
原文:使用HtmlAgilityPack批量抓取网页数据 相关软件点击下载登录的处理.因为有些网页数据需要登陆后才能提取.这里要使用ieHTTPHeaders来提取登录时的提交信息.抓取网页 Htm ...
随机推荐
- java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java heap space 原因:内存溢出,内存一直申请一直占用,无法回收 解决方法:定时重启下服务,
- pkg-config
可以使用pkg-config获取的库需要有一个条件,那就是要求库的提供者,提供一个.pc文件.比如gtk+-2.0的pc文件内容如下: prefix=/usrexec_prefix=/usrlibdi ...
- ansible playbook 示例
http://blog.keshi.org/hogememo/2015/12/07/exploiting-ansible-jinja2 http://blog.keshi.org/hogememo/2 ...
- 树型hierarchyid类型
--查询所有下级 DECLARE @BOSS hierarchyid --查询所有上级 DECLARE @Employee hierarchyid
- dede文章调用时过滤调 body里面的style属性和值
dede 发布文章的时候会在里面的标签中添加一些style 属性,现在改网站想去掉这些属性和里面的值,因为文章太多所以就用下面的方法 \include\arc.listview.class.php 在 ...
- Web 开发人员系统重装备忘录
准备工作: 一.配置IIS 软件安装: 一.大块头: 1.VS2005 1.VS2005SP1 2.VSS 2005 2.VS2008 1.VS2008TeamExplorer 2.VS2008SP1 ...
- 【Shell脚本】怎样表示一个for循环
[Shell脚本]怎样表示一个for循环 在此说一下我常用的两个结构: 1. for i in $(seq 1 100); do echo $i done 2. for (( i = ...
- XidianOJ 1041: Franky的游戏O
题目描述 Franky是super的人造人,来到了n*m的棋盘世界玩冒险游戏. n×m的棋盘由n行每行m个方格组成,左上角的方格坐标是(0,0),右下角的方格坐标是(n-1,m-1). 每次游戏时,他 ...
- iOS 解压打包静态库命令
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Hannotate SC" } p.p2 { margin: 0.0px ...
- mac 查看无线wifi的密码
finder->应用程序->实用工具->钥匙串访问->右上角输入wifi名查找->显示密码(需要管理员账号)