边学边写代码,记录下来。这段代码用于批量抓取主站下所有子网页中符合特定尺寸要求的的图片文件,支持中断。

原理很简单:使用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批量抓取站点图片的代码的更多相关文章

  1. 使用python来批量抓取网站图片

    今天"无意"看美女无意溜达到一个网站,发现妹子多多,但是可恨一个page只显示一张或两张图片,家里WiFi也难用,于是发挥"程序猿"的本色,写个小脚本,把图片扒 ...

  2. Hibernate学习---第十一节:Hibernate之数据抓取策略&批量抓取

    1.hibernate 也可以通过标准的 SQL 进行查询 (1).将SQL查询写在 java 代码中 /** * 查询所有 */ @Test public void testQuery(){ // ...

  3. Python3简单爬虫抓取网页图片

    现在网上有很多python2写的爬虫抓取网页图片的实例,但不适用新手(新手都使用python3环境,不兼容python2), 所以我用Python3的语法写了一个简单抓取网页图片的实例,希望能够帮助到 ...

  4. 使用IDM批量抓取音效素材下载

    IDM下载器的站点抓取功能,能够抓取网站上的图片.音频.视频.PDF.压缩包等等文件.更重要的是,能够实现批量抓取操作,省时省力.今天就来看一下,如何用IDM巧妙的批量抓取音效素材. 1.进入音效合辑 ...

  5. 抓取网页图片的脚本(javascript)

    抓取网页图片的脚本(javascript) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24172223 脚本内容 (没有换行) ...

  6. PHP抓取远程图片教程(包含不带后缀图片)

    之前做微信登录开发时候,发现微信头像图片没有后缀名,传统的图片抓取方式不奏效,需要特殊的抓取处理.所以,后来将各种情况结合起来,封装成一个类,分享出来. 创建项目 作为演示,我们在www根目录创建项目 ...

  7. php远程抓取网站图片并保存

    以前看到网上别人说写程序抓取网页图片的,感觉挺神奇,心想什么时候我自己也写一个抓取图片的方法! 刚好这两天没什么事,就参考了网上一个php抓取图片代码,重点借鉴了 匹配img标签和其src属性正则的写 ...

  8. 百度UEditor编辑器关闭抓取远程图片功能(默认开启)

    这个坑娘的功能,开始时居然不知道如何触发,以为有个按钮,点击一下触发,翻阅了文档,没有发现,然后再网络上看到原来是复制粘贴非白名单内的图片到编辑框时触发,坑娘啊............... 问题又来 ...

  9. 使用HtmlAgilityPack批量抓取网页数据

    原文:使用HtmlAgilityPack批量抓取网页数据 相关软件点击下载登录的处理.因为有些网页数据需要登陆后才能提取.这里要使用ieHTTPHeaders来提取登录时的提交信息.抓取网页  Htm ...

随机推荐

  1. 网页手机wap2.0网页的head里加入下面这条元标签......

    网页手机wap2.0网页的head里加入下面这条元标签,在iPhone的浏览器中页面将以原始大小显示,并不允许缩放. <meta name="viewport" conten ...

  2. 巧用freemarker

    使用Freemarker宏进行可扩展式模块化编程 该文是转载而来,并非我本人所写,但是觉得真心不错,所以收藏一下 一.前言 今天的文章聊一下freemarker的一些特性:宏,我们将使用它写出一些模块 ...

  3. JVM内存模型与性能调优

    堆内存(Heap) 堆是由Java虚拟机(JVM,下文提到的JVM特指Sun hotspot JVM)用来存放Java类.对象和静态成员的内存空间,Java程序中创建的所有对象都在堆中分配空间,堆只用 ...

  4. git 撤销commit

    如果不小心commit了一个不需要commit的文件,可以对其进行撤销. 先使用git log 查看 commit日志 commit 422bc088a7d6c5429f1d0760d008d86c5 ...

  5. javascript数组的一些方法实例

    1 concat

  6. Android 打包

    1.数字签名(指的是我们打包程序时所用keystore的SHA1指纹) 2.debug打包,不能在android 市场上架,使用的签名是默认的签名,1年后失效:release打包使用的是自己的签名,可 ...

  7. DEM数据如何生成高程点

    这次给大家介绍一个arcgis里的实用功能:通过地形数据提取高程点. 首先做好准备工作: 1.地形数据下载获取 2.软件准备 locaspace viewer:http://rj.baidu.com/ ...

  8. Gson运用

    输出对象或者对象的list时,我们一般都是重写toString,和遍历list,但是使用Gson输出对象或者对象的list会非常方便. Gson输出list或者对象.Gson数据没有格式化. impo ...

  9. curl post方法

    * [curl_post curl post方式请求接口] * @param [type] $url [接口的url] * @param [type] $data [传递的参数] * @return ...

  10. 如何在一台电脑上开启多个tomcat

    大家基本上都只在一台电脑上面启动一个Tomcat,而启动多个Tomcat会提示报错等相关故障.而假如调试负载均衡及集群的时候,需要在一台电脑上面开启多个Tomcat,那么怎么开启呢? 首先需要知道的是 ...