爬取一个超大级规划图的历程,嗯,有点坑。Python实现,低配电脑多线程方案。

本文主要是介绍爬取一个超大级规划图的历程,嗯,有点坑。Python实现,低配电脑多线程方案。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

         三天前,在一个Python技术交流群里面,一个朋友发出了一条消息,说爬取一个网站的放大级别最大的图,爬取下来。而且是有偿,当时我就想,这个地图我应该可以试试,然后点击网址(当时把网址也一起发出来了)然后放大到最大,看了一下,感觉不会太好爬取,然后我就问跟他私聊了一下,想试一下,如果有比我速度更快的请跟我说,我先分析一下,看看多久能爬去完。跟他说了以后,就开始分析网页,然后一点一点的抓取网页内的各种资源信息,一点一点的分析看看哪一些是我需要的资源。
          我的分析思路是这样的:
点进网址看到的是这样的,分析网页元素:

现在需要我做的就是将地图色块放大到最大,然后将整张图片下载下来。
然后我就看,这个网页的元素不算太多,会不会是用js控制div显示的图片呢?然后我继续分析网页,看到有一个iframe标签,,将鼠标放在上面好,正好在网页中是地图的区域,果断用链接进去,看到的网页是这样的。

这一下把好多没用的网页标签元素都去掉了,让人眼前一清晰,然后继续上面那一步,开始分析网页元素,用浏览器的Select an Element in the Page (快捷键ctrl+shift+C)然后定位到一个svg标签,这不是定义用于网络的基于矢量的图形的标签吗?果断进去看每个标签分析,然后继续用select an element 里面的但是,进去后,啥也没有啊,

而且根据里面的分析,还是一个hidden的svs   下面的g标签也是“display:block”的,很明显没显示啊,估计是用来故意防止反爬的吧,但是看到图片就在眼前不可能没有数据接口啊。所以我继续努力分析,
点开network以后发现里面又好多png的图片啊,

这应该是我所想要的图片了吧,我将图片打开,点开之后是一个下载地址,嗯,果断下载下来看一下,还真让我找到了,还真是,不过是缩小到最小的图的一部分,我然后将他放大以后再试试,放大以后,继续点开图片,下载,是我想要的图,但是,下载下来不是一整张图,而是一整张图的一小块。这就很尴尬了,放大到这么大,然后下载下来的图片只有这一小部分,这就有点尴尬了。虽然找到图了,但是对于一整张下载下来的话,得有多少张这样小的图呢?而且,从左上角开始分析,第一张图里面的并没有什么东西啊。有点小难度啊。
然后我开始跟那兄弟沟通,是不是只需要有色块的就可以,红线的就可以不需要了?经过一系列的沟通获取同意后,然后我开始测试,分析网站地址http://27.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/tile/1/1051/1463 后边的数保留,每次下载的图片都是最后数的数值为名称的png图片,我把数字简单修改以后,一样也可以下载,但是那么大的图,肯定不可能以前多张,是不是倒数二级目录也可以修改下载呢?这样我就下载了一下1050/1463    1051/1463      1050/1462   这三个地址所对应的图片,然后根据图片分析,倒数第二个目录代表y轴最后一级的目录代表的是x轴,所以,倒数第三个目录又是什么?我放大缩小之后查看network里面png所对应的地址,发现,当第三级有1-9个,当到了9的时候也就说明图片级别最大了。所以我将地图放大到9级然后,查看色块区域,这里我又返回到了element里面查看元素,既然又图片肯定应该有img标签元素或者是其他标签元素来将图片显示吧?经过我的努力分析还真让我给找到了。
就在svg标签上一层的div标签里面。既然人家需要有色块的区域内,那我就将这一块区域内上下左右的最靠边的四张图片的xy轴所对应的目录级别找到就可以了啊。将整个有色区域开始圈在一个矩形内。
找到后,好了,分析完成了,那我们就开始写代码吧。由于考虑到分析不全,怕上下左右找到的不是最靠边的,所以我就分别往外为扩展了一下,找到的坐标分别是上(187228,134402)下(187167,134620)左(187122,134455)右(187380,134539),我的天呢。这样一算,大概需要220*260张图片,大概57200张图片,根据测试下载下来的图片宽高像素都是256,这样一算,图片不小啊。

然后开始写代码,由于前面主要的分析思路已经完成了,现在主要就是访问图片地址获取图片就可以了。
好了,开始我的代码表演,直接上Request模块,都不需要用bs4或者是selenium模块的,因为直接获取的就是图片。

导入模块:

import threading
import time
from urllib import request
from urllib import error
import os
import socket

定义函数,ypx为Y轴。xpx为X轴。从上往下开始,横向下载,当没行x爬取完成后会y加一,然后继续爬取,当然了,是一行一行爬取的,所以我就需要每一行都要保存在一个文件加下面,就以y轴为名称,建立文件夹,保存在里面吧。
 

def mian(ypx,n):   #url8 = '资源网址/tile/8/'headers = {"Referer": "资源网址/map.html","User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"}path = "I:\map"xpx = 187121 #121y = ypx+3socket.setdefaulttimeout(30)while True:num = 0while True:try:if xpx < 187382:url = url8 + str(ypx) + "/" + str(xpx)print(n,"线程的下载",url)try:req = request.Request(url, headers=headers)html = request.urlopen(req)savePng(mkdirAndReturnNmae(path + "\\" + str(ypx), xpx), html.read())html.close()xpx += 1time.sleep(1)num = 1except ConnectionResetError  as  rese:print(n,rese)xpx -= 1time.sleep(5)print(n,"————————————————————————————————————————等待五秒。。。。")continueexcept socket.timeout as  stout:print(n,stout)xpx -= 1time.sleep(5)print(n,"————————————————————————————————————————等待五秒。。。。")continueexcept TimeoutError as  timeout:print(n, timeout)xpx -= 1time.sleep(5)print(n, "————————————————————————————————————————等待五秒。。。。")continueelse:xpx = 187121breakexcept error.HTTPError as e:print(n,"HttpError 跳过 ", e)time.sleep(0.5)xpx += 1print(n , "线程    ",xpx)# html.close()if num == 1:xpx = 187121break# continueypx += 1if ypx >= y:print(n,"线程  即将结束 ",ypx)print(n,".。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。请求结束。。。。。")exit(0)time.sleep(1)

嗯,因为考虑到服务器端那边可能会防止爬取,所以,每次获取一次图片,都会sleep(1),因为这么高强度,持续性的获取图片,服务器可能会认为是恶意攻击,所以,会有ConnectionResetError的错误(就是服务器强制断开链接),避免出现这个错误,利用try except 避免,except执行的函数,当出现这个错误的时候,会x轴返回一个,然后,sleep(5),,continue继续执行,而且,在服务器的reponse的返回后,获取完了图片要close()一下。这样可以在一定程度上避免服务器强制断开链接。在运行的时候,多次遇到TimeoutError,所以我导入了socket模块,设置一下等待时间socket.setdefaulttimeout(30),好像是我设置位置的问题,并没有有效避免这个问题,经常被except捕获到TimeoutError。所以在时间上,有很大程度的限制。嗯,避免这些问题以后,就开始爬取了,但是我的电脑配置有点底呀,而且,自己也没有服务器,分布式爬虫运用的现在也不太好,我就考虑运用多线程爬取。不过效果还行,如果是单线程话,五万多张近六万张图片每个sleep(1)一下,排除其他因素对时间的影响,还需要16个小时呢。如果多开几个线程的话,应该能够可以有效的节约一定的时间吧。所以,导入threading模块。
自定义线程类,继承thread类:
 

class MyThread(threading.Thread):"""属性:target: 传入外部函数, 用户线程调用args: 函数参数"""def __init__(self, target, args,krgs):super(MyThread, self).__init__()  # 调用父类的构造函数self.target = targetself.args = argsself.krgs= krgsdef run(self):self.target(self.args,self.krgs)

由于不需要太多的其他处理,所以简单定义一下。

下面是定义多个线程,开始线程的函数:
 

def main():mh1 = MyThread(mian,134599,1)  #574 开始+10mh2 = MyThread(mian,134602,2)  #584mh1.start()mh2.start()k=time.time()

 




好了,下面的代码是创建目录保存图片data的函数,自行了解就好。
 

def mkdirAndReturnNmae(path, idname):  # 创建保存目录并返回保存路径及名称if os.path.isdir(path):name = os.path.join(path, str(idname) + ".png")return nameelse:os.mkdir(path)name = os.path.join(path, str(idname) + ".png")return name

保存data

def savePng(name, data):file = open(name, 'wb')file.write(data)# print(name)file.close()


经过多层分析,以及处理,用我的小电脑用了三个多小时爬取下来了这些图片。

 

可是又有一个问题,需要我处理,我的电脑配置有点低,我应该怎么给他合成呢?有点难度,但是,通过查看前辈们的博客,还是找到了处理方法。下一篇文章继续写。爬取这一块已经完成。如果有更好的处理方法的话,还请大佬们多多赐教。小弟在这里提前感谢一下。

 

 

这篇关于爬取一个超大级规划图的历程,嗯,有点坑。Python实现,低配电脑多线程方案。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/689329

相关文章

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java进行文件格式校验的方案详解

《Java进行文件格式校验的方案详解》这篇文章主要为大家详细介绍了Java中进行文件格式校验的相关方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、背景异常现象原因排查用户的无心之过二、解决方案Magandroidic Number判断主流检测库对比Tika的使用区分zip

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义