偶然,想爬取城市所有的公交和地铁线路。其实通过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来保存。
点击这个,会出现一个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;