一个Python3批量抓取站点图片的程序

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

原理很简单:使用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等。这种直接调用的方式能够为每一个图片分配多线程进行下载。实现方式也最简单。

时间: 2025-01-17 12:07:25

一个Python3批量抓取站点图片的程序的相关文章

Python3批量爬取网页图片

所谓爬取其实就是获取链接的内容保存到本地.所以爬之前需要先知道要爬的链接是什么. 要爬取的页面是这个:http://findicons.com/pack/2787/beautiful_flat_icons 里面有很多不错的图标,目标就是把这些文件图片爬下来,保存成本地图片. 用python3怎么做呢? 第一步:获取要爬取的母网页的内容 import urllib.request import re url = "http://findicons.com/pack/2787/beautiful_f

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

今天"无意"看美女无意溜达到一个网站,发现妹子多多,但是可恨一个page只显示一张或两张图片,家里WiFi也难用,于是发挥"程序猿"的本色,写个小脚本,把图片扒下来再看,类似功能已有不少大师实现了,但本着学习锻炼的精神,自己折腾一遍,涨涨姿势! 先来效果展示下: python代码: # -*- coding:utf8 -*- import urllib2 import re import requests from lxml import etree import

Python3简单爬虫抓取网页图片

现在网上有很多python2写的爬虫抓取网页图片的实例,但不适用新手(新手都使用python3环境,不兼容python2),所以我用Python3的语法写了一个简单抓取网页图片的实例,希望能够帮助到大家,并希望大家批评指正. 1 import urllib.request 2 import re 3 import os 4 import urllib 5 #根据给定的网址来获取网页详细信息,得到的html就是网页的源代码 6 def getHtml(url): 7 page = urllib.r

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

1.hibernate 也可以通过标准的 SQL 进行查询 (1).将SQL查询写在 java 代码中 /** * 查询所有 */ @Test public void testQuery(){ // 基于标准的 sql 语句查询 String sql = "select * from t_person"; // 通过 createSQLQuery 获取 SQLQuery,而 SQLQuer 是 Query的子类 SQLQuery query = session.createSQLQue

Python -- 网络编程 -- 抓取网页图片 -- 图虫网

字符串(str)编码成字节码(bytes),字节码解码为字符串 获取当前环境编码:sys.stdin.encoding url编码urllib.parse.quote() url解码urllib.parse.unquote() 列表去重:pages = list(set(pages)) 创建文件夹(可多级创建):os.makedirs(folder)  os.mkdir()只能单级创建 首先分析网页(图虫网)的URL规律: 根网页地址形如: http://tuchong.com/tags/人像/

Hibernate批量抓取

1.应用场景 当我们想获取全部的商品类别,然后在获取所有类别下面的商品时,为了提高效率,就可以考虑使用批量抓取. 批量抓取使用映射文件中的set标签的batch-size属性来设置,其值是任意一个整数,值越大效率越高. (1)不使用批量抓取实现效果: 代码: @Test public void Test(){ SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { ses

抓取MM图片的爬虫

刚学python,试着写了个非常简单的爬虫,爬一些MM的鲍照下来.记录一下 #coding=utf-8 import urllib,time import re global x x=0 def getHtml(url): page = urllib.urlopen(url) html = page.read() return html def getImg(html): global x reg = r'original=\'(.+?.jpg)\' width' imgre = re.comp

Python爬虫抓取网页图片

本文通过python 来实现这样一个简单的爬虫功能,把我们想要的图片爬取到本地. 下面就看看如何使用python来实现这样一个功能. # -*- coding: utf-8 -*- import urllib import re import time import os #显示下载进度 def schedule(a,b,c): ''''' a:已经下载的数据块 b:数据块的大小 c:远程文件的大小 ''' per = 100.0 * a * b / c if per > 100 : per =

抓取随机图片

最近收集了一些随机图片网址,想把这些图片全部抓取下来,到网上搜了搜,都只有抓取链接的,没有抓取图片的,这时正好看到了VariousArtist的抓图自动机,赶紧下了个Python(我是C++党)来试试,结果发现-- 这份代码实在是太!鸡!肋!了!,运行一次只能抓一张图片,如果靠人工点的话岂不是要点到地老天荒,于是,我编写了一个.bat程序和一个C++程序,用来配合那份Python代码,一次抓取多张图片. 具体步骤如下: 1.配置好Python和C++废话! 2.在E盘中新建一个文件夹Photo(