使用chrome扩展程序爬取地图数据

偶然,想爬取城市所有的公交和地铁线路。其实通过8684网站就可以爬取到了。

但是好像不够完整,就想从高德地图抓取。

阿里的产品也太难了。对新手而言,只会简单的post请求显然不足以完成任务。

其实不管什么网站,抽象起来就是获取数据,保存,分析而已。对简单的任务,爬虫用什么语言,就用该语言完成所有任务就好了。

对地图数据,只是获取数据,就几乎是不可能的,就没有后文了。

好在,获取数据最直接的方式就是浏览器一个页面一个页面的访问。

也就是直接用js来发出请求。chrome里面,就是以扩展程序的方式进行。知名的有web scrapper。不过估计对地图数据也没有太大的用处,难点在于服务器的请求验证。

比如我浏览器直接打开30个标签页,进行请求数据,就可能因为你访问过多,直接给你丢个滑块验证。

或者说,你打开一个标签页,5s刷新一次请求,次数多了,还是会让你滑块验证。

这就没办法了。本人并不会js。更别说是移动滑块了。

直接给出代码吧。

manifest.json
{
    "name": "My Extension",
    "version": "0.1",
    "manifest_version": 3,
    "description": "Does some simple stuff",
    "background": {
      "service_worker": "background.js"
    },
    "action": {
      "default_icon": "logo.png"
    },
    "permissions": ["tabs"]
  }
  
background.js
// 定义一个数组,存放要切换的url
 const line = `轨道交通1号线 轨道交通2号线 轨道交通3号线 轨道交通4号线 轨道交通5号线 轨道交通6号线 轨道交通7号线 轨道交通8号线 轨道交通9号线 轨道交通10号线 轨道交通环线内环 轨道交通环线外环`;
// 定义一个变量,用于存储所有的链接
let urls = [];

// 把字符串按空格分割为数组
let arr = line.split(" ");
// 遍历数组,对每个字符串进行URL编码并拼接成完整的URL
for (let s of arr) {
  let encodedStr = encodeURIComponent(s);
  let baseUrl = "https://ditu.amap.com/search?city=500000&query=";
  //baseUrl = `https://ditu.amap.com/service/poiInfo?query_type=TQUERY&pagesize=20&pagenum=1&qii=true&cluster_state=5&need_utd=true&utd_sceneid=1000&div=PC1000&addr_poi_merge=true&is_classify=true&zoom=8.29&city=500000&geoobj=103.70459%7C27.876082%7C110.741422%7C31.278651&keywords=`;
//   baseUrl = "http://192.168.133.1:9999/index.html?keywords=";
  let fullUrl = baseUrl + encodedStr;
  // 把完整的URL添加到urls数组中
  urls.push(fullUrl);
}
  
 
  
  // 定义一个变量,记录当前的url索引
  var index = 0;//不断地修改,然后重新加载扩展

  // 定义一个函数,用来生成一个5-10之间的随机数
function getRandomSleepTime() {
    // 生成一个0-1之间的随机数
    var random = Math.random();
    // 乘以5,得到一个0-5之间的随机数
    var range = random * 10;
    // 加上5,得到一个5-10之间的随机数
    var sleepTime = range + 5;
    // 返回这个随机数
    return sleepTime;
  }
  
  function getRandomSleepTime1() {
    // 生成一个0-1之间的随机数
    var random = Math.random();
    // 乘以5,得到一个0-5之间的随机数
    var range = random * 5;
    // 加上5,得到一个5-10之间的随机数
    var sleepTime = range + 5;
    // 返回这个随机数
    return sleepTime;
  }
 

  
  function openTabUrl(tabId) {
    // 如果索引超出了数组长度,说明已经打开完所有链接,结束递归
    if (index >= urls.length) {
        console.log("finish");
      return;
    }
    // 获取当前要打开的url
    console.log("index = ",index," url = ",arr[index]);//日志很重要,结合保存的文件,就能发现从哪个index开始,就失败了。就修改index的初始值,再重新加载扩展。
    var url = urls[index];
    // 更新标签页的url为当前url
    chrome.tabs.update(tabId, {url: url}, function(tab) {
      // 监听tabs.onUpdated事件来检测标签页是否加载完成
      chrome.tabs.onUpdated.addListener(function listener(tabId, info) {
        if (info.status === 'complete' && tabId === tab.id) {
          // 移除监听器,避免重复触发
          chrome.tabs.onUpdated.removeListener(listener);
          // 增加索引,准备打开下一个url
          index++;
          // 判断是否需要休眠
          if (index % 5 == 0) {
            // 在休眠5秒后继续递归调用函数
            // setTimeout(openTabUrl, 5000, tabId);
             // 在需要休眠的地方,调用这个函数,并把它作为setTimeout的第二个参数
            setTimeout(openTabUrl, getRandomSleepTime() * 1000, tabId);
          } else {
            // 如果不需要休眠,就直接递归调用函数
            setTimeout(openTabUrl, getRandomSleepTime1() * 1000, tabId);
          }
        }
      });
    });
  }

  // 监听用户点击扩展图标的事件
chrome.action.onClicked.addListener(function(tab) {
    // 获取urls数组中的第一个链接
   /* let url = urls.shift();
    // 如果有链接,就打开指定链接的标签页
    if (url) {
        openTabUrl(url);
    }*/
    chrome.tabs.create({active: true}, function(tab) {
        // 调用函数,传入标签页的id
        openTabUrl(tab.id);
      });
  });

line总计有1000条左右,为了简洁点,这里就缩短了line。可以不断的修改index,再重新加载扩展,因为经常会因为滑块导致失效。

验证太麻烦了,哪怕我经常sleep来请求,还是会被限制。
至于请求的数据,我使用fiddler来保存。

image-20230616122042613

点击这个,会出现一个Fiddler ScriptEditor

static function OnBeforeResponse(oSession: Session)

找到这个函数,在末尾添加如下代码。

if ((oSession.responseCode == 200) && oSession.fullUrl.Contains("ditu.amap.com/service/poiInfo")||oSession.fullUrl.Contains("192.168.133.1"))
		{
			var uri = new Uri(oSession.fullUrl);

			var query = HttpUtility.ParseQueryString(uri.Query);
			var keyword = query["keywords"]; // keywords就是搜索关键词,比如 10路
			oSession.utilDecodeResponse();
			oSession.SaveResponseBody("D:\\temp\\t\\" + keyword + ".txt");
		}

//对了,还要在顶部添加两行。
import Syste.IO;
import System.Web;
就可以自动保存线路数据了。这其实也是上面js代码里面注释的baseUrl。我试过浏览器直接请求第2条,然后没几次,浏览器就处于封禁状态了。

所以,还是老老实实的使用baseUrl的第一条链接,访问它,它会自己加载注释那条链接,虽然会慢一些,但是不至于被封禁。

代码整体来自于bing,还了解了一些webscoket的知识。兴许什么时候可以和其他语言进行通信,以配合完成任务。不会JS,也是个硬伤啊。

之前还想过爬取boss直聘的数据,但是直接用go编程爬取好像也挺复杂的。
偶然看见这篇帖子,还真是方便啊。
chrome插件,实现爬虫

posted @ 2023-06-16 12:33  念秋  阅读(75)  评论(0编辑  收藏  举报