从Google Map爬数据
在这篇博文中,笔者从实验的角度,从爬数据的困难出发,阐述如何从Google Map上爬地图数据。本文的出发点为实验,而非商用。Google Map对其自己的数据具有其权益,希望读者以博文为学习实验之用,不要将自己所爬到的数据用于商用。如果因为此类事件所引起的纠纷,笔者概不负责。笔者也希望,大家在看到此博文后,能够进一步改进其数据的安全性。
笔者在实验室某个GIS项目中必须需要一定数据级的地图数据。在百般无奈下,笔者开始从Google Map爬数据。从Google Map上采集一定量的数据有作实验。
从Google Map爬数据的原理
笔者使用GoogleChrome来查看Google Map的Resources,图如下:
x=0&y=0&z=0 |
x=0&y=0&z=1 | x=1&y=0&z=1 |
x=0&y=1&z=1 | x=1&y=1&z=1 |
我们可以得知,x=xx,y=yy,z=zz的这块数据,所在的图层为zz层,该图层中每块数据的经度差为360/2^zz,纬度差为180/2^zz,左上角的经纬度为(360/2^zz*xx-180, 180/2^zz*yy-90)。同样,我们也可从一个数据块的左上角经纬度反推出这个文件在zz层的x与y。这也就是我们从Google Map爬数据的原理。
从Google Map爬数据有何难点?
1. 在国内由于政治等原因,连接Google服务器会有所中断。
3. 单线程操作的效率太低,多线程情况下,效率会有很大提升。
4. Google服务器会对每个请求检查,判断是否来自浏览器还是来自爬虫。
5. 对于已下载的文件无须下载,即爬虫必须拥有“断点续传”的功能。不能由于网络的中断或者人为的中断,而导致之前的进度丢失。
对于这些难点有何解决方案
3. 单线程操作的效率太低,我们需要使用多线程。但是,在使用多线程时,由于每一个文件的大小都很小,因而我们设计多线程机制时,每一个线程可以负责下载若干个文件。而不同的线程所下载的文件之间,没有交集。
4. 对于第4点,我们可以在建立http连接时,设置”User-Angent”,例如:
- httpConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
- httpConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
5. 对于第5点,我们可以在每下一个文件之间,事先判断文件是否已经完成。这有很多种解决方法,笔者在这里,采用file.exists()来进行判断。因为,对于下载一个文件而言,检查文件系统上某一个文件的代价会小很多。
改进与具体实现
其中,分成三个模块:Downloader, DownloadThread, ProxyConfig。Downloader负责初化化线程池以存放DownloaderThread。每一个DownloadThread都会负责相应的若干个切图数据的下载。DownloadThread从ProxyConfig那里去获取代理,并从文件系统中检查某一个文件是否已经下载完成,并将下载完成文件按一定的规则存储到文件系统中去。ProxyConfig会从www.18daili.com更新现有的代理,在笔者的系统,每取1024次代理,ProxyCofig就会更新一次。
原码
- package ??;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class Downloader {
- private static int minLevel = 0;
- private static int maxLevel = 10;
- private static String dir = "D:\\data\\google_v\\";
- private static int maxRunningCount = 16;
- private static int maxRequestLength = 100;
- public static void download() {
- ExecutorService pool = Executors.newFixedThreadPool(maxRunningCount);
- for (int z = minLevel; z <= maxLevel; z++) {
- int curDt = 0;
- int requests[][] = null;
- int maxD = (int) (Math.pow(2, z));
- for (int x = 0; x < maxD; x++) {
- for (int y = 0; y < maxD; y++) {
- if (curDt % maxRequestLength == 0) {
- String threadName = "dt_" + z + "_" + curDt;
- DownloadThread dt = new DownloadThread(threadName, dir, requests);
- pool.execute(dt);
- curDt = 0;
- requests = new int[maxRequestLength][3];
- }
- requests[curDt][0] = y;
- requests[curDt][1] = x;
- requests[curDt][2] = z;
- curDt++;
- }
- }
- DownloadThread dt = new DownloadThread("", dir, requests);
- pool.execute(dt);
- }
- pool.shutdown();
- }
- public static void main(String[] strs) {
- download();
- }
- }
DownloadThread:
- package ??;
- import java.io.BufferedInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.Proxy;
- import java.net.URL;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class DownloadThread extends Thread {
- private static int BUFFER_SIZE = 1024 * 8;// 缓冲区大小
- private static int MAX_TRY_DOWNLOAD_TIME = 128;
- private static int CURRENT_PROXY = 0;
- private String threadName = "";
- private String dir;
- // private int level;
- private String tmpDir;
- private Proxy proxy;
- private int[][] requests;
- private String ext = ".png";
- private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- public DownloadThread(String threadName, String dir, int[][] requests) {
- this.threadName = threadName;
- this.dir = dir;
- this.requests = requests;
- }
- @Override
- public void run() {
- Date now = new Date();
- System.out.println(dateFormat.format(now) + "\t" + threadName + ":\t开始运行");
- long t1 = System.currentTimeMillis();
- long totalLength = download();
- long t2 = System.currentTimeMillis();
- double speed = (double) totalLength / (t2 - t1);
- now = new Date();
- if (speed < 0.5) {
- CURRENT_PROXY++;
- }
- System.out.println(dateFormat.format(now) + "\t" + threadName + ":\t完成运行\t" + speed + "kB/s");
- }
- public long download() {
- long totalLength = 0;
- if (requests == null) {
- return 0;
- }
- //System.out.println(requests.length);
- for (int i = 0; i < requests.length; i++) {
- int yy = requests[i][0];
- int xx = requests[i][1];
- int zz = requests[i][2];
- int yyg = (int) (Math.pow(2, zz) - 1 - requests[i][0]);
- this.tmpDir = dir + "/tmp/" + zz + "/";
- File tmpDirFile = new File(tmpDir);
- if (tmpDirFile.exists() == false) {
- tmpDirFile.mkdirs();
- }
- String dirStr = dir + "/download/" + zz + "/" + yy + "/";
- File fileDir = new File(dirStr);
- if (fileDir.exists() == false) {
- fileDir.mkdirs();
- }
- String fileStr = dirStr + yy + "_" + xx + ext;
- File file = new File(fileStr);
- // double lat1 = (yy) * dDegree - 90;
- // double lat2 = (yy + 1) * dDegree - 90;
- String url = "http://mt0.google.com/vt/lyrs=m@174000000&hl=zh-CN&src=app&x=" + xx + "&y=" + yyg + "&z=" + zz
- + "&s=";
- // System.out.println(url);
- if (file.exists() == false) {
- String tmpFileStr = tmpDir + yy + "_" + xx + ext;
- boolean r = saveToFile(url, tmpFileStr);
- if (r == true) {
- totalLength += cut(tmpFileStr, fileStr);
- Date now = new Date();
- System.out.println(dateFormat.format(now) + "\t" + threadName + ":\t" + zz + "\\" + yy + "_" + xx + ext + "\t"+proxy+"\t完成!");
- } else {
- Date now = new Date();
- System.out.println(dateFormat.format(now) + "\t" + threadName + ":\t" + zz + "\\" + yy + "_" + xx + ext + "\t"+proxy+"\t失败!");
- }
- } else {
- Date now = new Date();
- System.out.println(dateFormat.format(now) + "\t" + threadName + ":\t" + zz + "\\" + yy + "_" + xx + ext + "已经下载!");
- }
- }
- return totalLength;
- }
- public static long cut(String srcFileStr, String descFileStr) {
- try {
- // int bytesum = 0;
- int byteread = 0;
- File srcFile = new File(srcFileStr);
- File descFile = new File(descFileStr);
- if (srcFile.exists()) { // 文件存在时
- InputStream is = new FileInputStream(srcFileStr); // 读入原文件
- FileOutputStream os = new FileOutputStream(descFileStr);
- byte[] buffer = new byte[1024 * 32];
- // int length;
- while ((byteread = is.read(buffer)) != -1) {
- // bytesum += byteread; //字节数 文件大小
- // System.out.println(bytesum);
- os.write(buffer, 0, byteread);
- }
- is.close();
- os.close();
- }
- srcFile.delete();
- return descFile.length();
- } catch (Exception e) {
- System.out.println("复制单个文件操作出错");
- e.printStackTrace();
- }
- return 0;
- }
- public boolean saveToFile(String destUrl, String fileName) {
- int currentTime = 0;
- while (currentTime < MAX_TRY_DOWNLOAD_TIME) {
- try {
- FileOutputStream fos = null;
- BufferedInputStream bis = null;
- HttpURLConnection httpConnection = null;
- URL url = null;
- byte[] buf = new byte[BUFFER_SIZE];
- int size = 0;
- // 建立链接
- url = new URL(destUrl);
- // url.openConnection(arg0)
- currentTime++;
- proxy = ProxyConfig.getProxy(CURRENT_PROXY);
- //if (proxy != null) {
- // System.out.println(threadName + ":\t切换代理\t" + proxy.address().toString());
- //} else {
- // System.out.println(threadName + ":\t使用本机IP");
- //}
- if (proxy == null) {
- httpConnection = (HttpURLConnection) url.openConnection();
- } else {
- httpConnection = (HttpURLConnection) url.openConnection(proxy);
- }
- httpConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
- httpConnection.setConnectTimeout(60000);
- httpConnection.setReadTimeout(60000);
- // 连接指定的资源
- httpConnection.connect();
- // 获取网络输入流
- bis = new BufferedInputStream(httpConnection.getInputStream());
- // 建立文件
- fos = new FileOutputStream(fileName);
- // System.out.println("正在获取链接[" + destUrl + "]的内容;将其保存为文件[" +
- // fileName + "]");
- // 保存文件
- while ((size = bis.read(buf)) != -1){
- // System.out.println(size);
- fos.write(buf, 0, size);
- }
- fos.close();
- bis.close();
- httpConnection.disconnect();
- // currentTime = MAX_TRY_DOWNLOAD_TIME;
- break;
- } catch (Exception e) {
- //e.printStackTrace();
- CURRENT_PROXY++;
- }
- }
- if (currentTime < MAX_TRY_DOWNLOAD_TIME) {
- return true;
- } else {
- return false;
- }
- }
- }
ProxyConfig:
- package org.gfg.downloader.google.vctor;
- import java.net.InetSocketAddress;
- import java.net.Proxy;
- import java.net.Proxy.Type;
- import java.net.URL;
- import java.net.URLConnection;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- public class ProxyConfig {
- private static List<Proxy> proxies;
- private static int getTime = 0;
- @SuppressWarnings("unchecked")
- public static void inital() {
- // if (proxies == null) {
- proxies = null;
- proxies = new ArrayList<Proxy>();
- // } else {
- // proxies.clear();
- // }
- try {
- URL url = new URL("http://www.18daili.com/");
- URLConnection urlConnection = url.openConnection();
- urlConnection.setConnectTimeout(30000);
- urlConnection.setReadTimeout(30000);
- SAXReader reader = new SAXReader();
- // System.out.println(url);
- reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
- Document doc = reader.read(urlConnection.getInputStream());
- if (doc != null) {
- Element root = doc.getRootElement();
- Element proxyListTable = getElementById(root, "proxyListTable");
- // System.out.println(proxyListTable.asXML());
- Iterator<Element> trs = proxyListTable.elementIterator();
- trs.next();
- while (trs.hasNext()) {
- Element tr = trs.next();
- Iterator<Element> tds = tr.elementIterator();
- String ip = tds.next().getText();
- String port = tds.next().getText();
- // System.out.println(ip+":"+port);
- Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(ip, Integer.valueOf(port)));
- proxies.add(proxy);
- System.out.println("添加代理\t" + proxy);
- }
- }
- } catch (Exception e) {
- // e.printStackTrace();
- }
- }
- private static Element getElementById(Element element, String id) {
- Element needElement = null;
- Iterator<Element> subElements = element.elementIterator();
- while (subElements.hasNext()) {
- Element subElement = subElements.next();
- String getId = subElement.attributeValue("id");
- if (getId != null && getId.equals(id)) {
- needElement = subElement;
- break;
- } else {
- needElement = getElementById(subElement, id);
- if (needElement != null) {
- break;
- }
- }
- }
- return needElement;
- }
- synchronized public static Proxy getProxy(int i) {
- getTime++;
- if (getTime % 1024 == 0 || proxies == null) {
- inital();
- getTime = 0;
- System.out.println("重新生成代理列表!");
- System.out.println("当前共有" + proxies.size() + "个代理!");
- }
- if (i % 8 == 0) {
- return null;
- }
- int index = i % proxies.size();
- index = Math.abs(index);
- return proxies.get(index);
- }
- public static void main(String... str) {
- inital();
- }
- }
如需转载,请标明出处:http://blog.csdn.net/JairusChan
从Google Map爬数据相关推荐
- 教你如何从Google Map爬数据
在这篇博文中,笔者从实验的角度,从爬数据的困难出发,阐述如何从Google Map上爬地图数据.本文的出发点为实验,而非商用.Google Map对其自己的数据具有其权益,希望读者以博文为学习实验之用 ...
- 教你如何从Google Map爬数据(切片)
转:http://blog.csdn.net/JairusChan 在这篇博文中,笔者从实验的角度,从爬数据的困难出发,阐述如何从Google Map上爬地图数据.本文的出发点为实验,而非商用.Goo ...
- google map 离线数据
1.固件必须是14948及以上版本5 2. 支持离线地图 的googlemap 5.0 版本下载地址 : 网盘下载: http://u.115.com/file/t678d5b927 3.地图软件 ...
- Python 爬取 Google Map POI
Google Map 的 API文档:https://developers.google.com/maps/documentation/places/web-service/search#PlaceS ...
- AMap + echarts、google map + d3.js分别实现数据可视化中的飞线图(迁徙图)
首先肯定是给出demo啦: 演示demo 直接到左侧选择框中选择View taxi flow里面随便选个日期 总体介绍 最近由于工作室项目需要做一个数据可视化平台,这个平台最终是交由国外人使用的.而国 ...
- Android特色开发之Google MAP
本文节选于机械工业出版社推出的<Android应用开发揭秘>一书,作者为杨丰盛.本书内容全面,详细讲解了Android框架.Android组件.用户界面开发.游戏开发.数据存储.多媒体开发 ...
- python爬虫怎么爬同一个网站的多页数据-如何用Python爬数据?(一)网页抓取
如何用Python爬数据?(一)网页抓取 你期待已久的Python网络数据爬虫教程来了.本文为你演示如何从网页里找到感兴趣的链接和说明文字,抓取并存储到Excel. 需求 我在公众号后台,经常可以收到 ...
- Google Map API 的基础使用
因为公司业务由国内市场到国际市场,有一些国际性业务的项目需要用到Google Map.项目完成后,把一些常用的方法写出来,供大家参考. 一.google地图基础显示 (1)引用google map j ...
- Google Map API V3开发(5)
Google Map API V3开发(1) Google Map API V3开发(2) Google Map API V3开发(3) Google Map API V3开发(4) Google M ...
最新文章
- UNIX下C语言的图形编程-curses.h函数库
- 下c语言按q退出_Linux vim编辑器怎么退出?第一次用都会问的问题
- memcpy和strcpy的区别及memcmp和strcmp的区别
- 用Linux命令行生成随机密码的十种方法
- 端口隔离配置命令、端口镜像(抓包配置)详解(附图,建议PC观看)
- CentOS:linux开放指定端口命令
- XStream 反序列化漏洞 (CVE-2020-26258 26259) 的复现与分析
- python装饰器详解-python装饰器详解
- 百度指数邀请序列号_腾讯第8款社交AppHood 上线;抖音内测云游戏、直播回放等新功能;百度推出多人视频社交App一起吧| 产品挖掘机...
- 反编译exe软件_挖洞经验 | Panda反病毒软件本地提权漏洞分析
- TopJui 我踩的那些坑
- 网上支付跨行清算系统与大小额支付系统有什么区别?
- [Shader2D]浮雕效果
- 图像处理 图像识别 模式识别 分类检测
- 第六天 黑马十次方 用户注册、用户登陆掌握js-cookie、微信扫码登陆、nuxt嵌套路由
- 使用ASMap构建高密度遗传图谱
- 广电网络电视怎么服务器连接中断,怎么解决广电网络看电视卡
- spd耗材管理流程图_医用耗材SPD管理模式详解
- SATA协议OOB随笔
- win10计算机跑分,Win11对比Win10系统性能测试,看完跑分结果还等发布会吗?
热门文章
- Axure源rp文件-线上电竞竞技赛事游戏直播比赛平台web
- DirectShow摄像头采集
- 内燃机汽车发动机工作原理-飞轮的作用
- python的knn算法list_机器学习实战学习笔记1——KNN算法
- 进入游戏后如何回到计算机界面,玩LOL胜利后点击“继续游戏”要等个将近10秒才能回到结算界面,请问是怎么回事?...
- 简单的excel表格格式整理
- Oracle表空间的管理方式(LMT、DMT)--本地和字典管理
- html中怎么让字自动变颜色,html如何设置单个字体颜色
- 国内银行应用软件项目外包模式探讨(转)_manok_新浪博客
- 【算法讲18:二次剩余】勒让德符号 | 欧拉判别法 | Cipolla 算法