51job search filter with distance

51job搜索结果以距离过滤

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name:zh-CN        	51job search filter with distance
// @name        	51job search filter with distance
// @namespace   https://github.com/zhuzemin
// @description:zh-CN  51job搜索结果以距离过滤
// @description  51job搜索结果以距离过滤
// @author      zhuzemin
// @include     https://search.51job.com/list/*
// @version     1.3
// @grant         GM_xmlhttpRequest
// @grant         GM_registerMenuCommand
// @grant         GM_setValue
// @grant         GM_getValue
// @grant         GM_addStyle
// @connect-src api.map.baidu.com
// @connect-src jobs.51job.com
// @run-at      document-end
// ==/UserScript==

let config = {
	'debug': false,
	'origin': GM_getValue('origin').replace(/\s/, '') || null,
	'origin_list': [],
	'max_distence': GM_getValue('max_distence') || 12000,
	'max_joblist': GM_getValue('max_joblist') || 10,
	'joblist': [],
	'button': null,
	'running': false,
	'api': {
		'baidu': {
			'url': `https://api.map.baidu.com/direction/v2/riding?origin={{origin}}&destination={{lat}},{{lng}}&ak={{ak}}`,
			'ak': [
				"RGBBNuGoAcxvzl02ibOAxGZM",
				'xop0xOYgFxbts1hZhT8YAS2o4BoKfDZp'
			],
			'getpoint': 'https://api.map.baidu.com/lbsapi/getpoint/index.html'
		},
		'51job': {
			'url': 'https://search.51job.com/jobsearch/bmap/map.php?jobid={{jobid}}'
		}
	},
}
let debug = config.debug ? console.log.bind(console) : function () {
};
debug(config.max_distence);
debug(config.max_joblist);

// prepare UserPrefs
setUserPref(
	'origin',
	config.origin,
	'设置家的坐标',
	`
(经度, 纬度), Example: "117.215491, 39.122174";
多个坐标, 以";"分隔;
*坐标来自百度地图: `+ config.api.baidu.getpoint
	,
);

setUserPref(
	'max_distence',
	config.max_distence,
	'设置距离上限',
	'骑行距离, 单位(米)'
);

setUserPref(
	'max_joblist',
	config.max_joblist,
	'搜索结果上限',
	'搜索结果上限'
);

class requestObject {
	constructor(url) {
		this.method = 'GET';
		this.respType = 'text';
		this.url = url;
		this.body = null;
		this.headers = {
			'User-agent': window.navigator.userAgent,
			'Referer': window.location.href,
		};
		this.mimeType = 'text/html;charset=utf8';
	}
}

async function init() {
	debug(config.origin);
	if (config.origin != null) {
		for (let origin of config.origin.split(';')) {
			let lat, lng;
			for (let item of origin.split(',')) {
				if (item.length == 9) {
					lat = item;
				}
				else {
					lng = item;
				}

			}
			config.origin_list.push({
				'lat': lat,
				'lng': lng
			});
		}
		debug(JSON.stringify(config.origin_list));
		config.button = document.createElement('button');;
		config.button.textContent = '按距离筛选';
		config.button.className = 'p_but';
		config.button.style.width = '100px';
		config.button.addEventListener('click', () => {

			config.joblist = [];
			config.running = true;
			filter();
		});
		document.querySelector('div.j_tlc').appendChild(config.button);
	}

}
window.addEventListener('DOMContentLoaded', init);

async function filter() {
	debug('filter');
	if (config.running) {
		config.button.textContent = "搜索中...";
		setTimeout(async () => {

			let j_joblist = document.querySelector("div.j_joblist");
			for (let item of j_joblist.childNodes) {
				let jobid = item.querySelector('input[name="delivery_jobid"').getAttribute('value');
				let url = config.api['51job'].url.replace('{{jobid}}', jobid);
				debug(url);
				let obj = new requestObject(url);
				obj.mimeType = 'text/html;charset=gb2312';
				await httpRequest(obj).then(async (resp) => {
					let dom = new DOMParser().parseFromString(resp.response, 'text/html');
					let script = dom.querySelector('script');
					debug(script.textContent);
					eval(script.textContent);
					let suc = false;
					for (let origin of config.origin_list) {
						if (g_company.lat > 0 && Math.abs(origin.lat - g_company.lat) <= 1 && Math.abs(origin.lng - g_company.lng) <= 1) {

							let rnd = Math.floor(Math.random() * config.api.baidu.ak.length);
							url = config.api.baidu.url.replace('{{ak}}', config.api.baidu.ak[rnd]);
							url = url.replace('{{origin}}', origin.lat + ',' + origin.lng);
							url = url.replace('{{lat}}', g_company.lat);
							url = url.replace('{{lng}}', g_company.lng);
							debug(url);
							obj = new requestObject(url);
							obj.respType = 'json';
							await httpRequest(obj).then((resp) => {
								if (resp.status == 200) {

									//0=ok
									if (resp.response.status == 0) {
										let distance = resp.response.result.routes[0].distance;
										debug(distance);
										if (distance > config.max_distence) {
											debug('jobid: ' + jobid + '; too far');
										}
										else {
											debug('jobid: ' + jobid + '; distance: ' + distance);
											config.joblist.push(item);
											suc = true;
										}

									}
									else {

										debug('jobid: ' + jobid + '; status error: ' + JSON.stringify(resp.response) + '; finalUrl: ' + resp.finalUrl);
									}
								}
							});
							if (suc) {
								debug('distance confort');
								break;
							}
						}
						else {
							debug(g_company.name);
						}

					}
					if (!suc) {
						item.style.display = "none";
					}
				});

			}
			let page_num = document.querySelector('div.rt.rt_page');
			let arr = page_num.textContent.match(/(\d+)\s\/\s(\d+)/);
			let current = parseInt(arr[1]);
			let total = parseInt(arr[2]);
			debug(current + '/' + total);
			debug('config.joblist: ' + config.joblist.length);
			debug('config.max_joblist: ' + config.max_joblist);
			if (config.joblist.length < config.max_joblist && current < total) {
				debug('config.joblist: ' + config.joblist.length);
				config.running = true;
				page_num.querySelector('a.e_icons.i_next').click();
				await filter();
			}
			else {
				for (let item of config.joblist) {
					let jobid = item.querySelector('input[name="delivery_jobid"').getAttribute('value');
					for (let node of j_joblist.childNodes) {
						let node_jobid = node.querySelector('input[name="delivery_jobid"').getAttribute('value');
						if (jobid == node_jobid) {

							break;
						}
						else if (node == j_joblist.lastChild) {

							j_joblist.appendChild(item);
						}
					}
				}
				debug('suc');
				config.button.textContent = "按距离筛选";
				config.running = false;
			}
		}, 1000);

	}
}

/**
 * Create a user setting prompt
 * @param {string} varName
 * @param {any} defaultVal
 * @param {string} menuText
 * @param {string} promtText
 * @param {function} func
 */
function setUserPref(varName, defaultVal, menuText, promtText, func = null) {
	GM_registerMenuCommand(menuText, function () {
		var val = prompt(promtText, GM_getValue(varName, defaultVal));
		if (val === null) { return; }// end execution if clicked CANCEL
		GM_setValue(varName, val);
		if (func != null) {
			func(val);
		}
	});
}
function httpRequest(object, timeout = 10000) {
	return new Promise(
		(resolve, reject) => {
			GM_xmlhttpRequest({
				method: object.method,
				url: object.url,
				headers: object.headers,
				responseType: object.respType,
				overrideMimeType: object.mimeType,
				data: object.body,
				timeout: timeout,
				onload: function (responseDetails) {
					debug(responseDetails);
					//Dowork
					resolve(responseDetails);
				},
				ontimeout: function (responseDetails) {
					debug(responseDetails);
					//Dowork
					resolve(responseDetails);

				},
				ononerror: function (responseDetails) {
					debug(responseDetails);
					//Dowork
					resolve(responseDetails);

				}
			});
		}
	)
}