【请抓紧时间上车】实现一个12306的chrom插件
栏目: JavaScript · 发布时间: 5年前
内容简介:源码地址:刚过完年不久,相信大家还能回想到春运时被抢票支配的恐惧。但是本教程并不是教大家如何刷票的。半个月前我帮一个朋友买一张从宿州到上海的火车票,结果。。效果类似下图WTF:
源码地址: github.com/zjians/1230…
起因(吐槽):
刚过完年不久,相信大家还能回想到春运时被抢票支配的恐惧。但是本教程并不是教大家如何刷票的。半个月前我帮一个朋友买一张从宿州到上海的火车票,结果。。效果类似下图WTF:
于是想着买个中间站的票能上车也行,到车上再补票就好了,于是对着车次点了一下,将中间站的名称ctrl+c,ctrl+v一个一个查询有没有余票。一顿操作猛如虎,但是凭着 程序员 的自尊,emm这样不行,操作太傻了。于是周末便撸了这款插件:
嗯嗯,优雅,程序员的自尊又回来了
经过(开发过程):
首先打开chrome开发文档 crxdoc-zh.appspot.com/extensions/…
本来以为要刷很多文档,结果看了20分钟,嗯,感谢自己是个前端,会了。
首先基础工作就是定义一个manifest.json (清单文件),用于定义插件相关的配置。先贴一份本插件的配置文件(各项作用看注释),详细解释请看官方文档:
{ "manifest_version": 2, "name": "12306", "version": "1.0", "description": "查询当前车次各站点的余票", "author": "https://github.com/zjians/12306", "page_action": { "default_icon": { "16": "assets/icons/icon16.png", "48": "assets/icons/icon48.png", "128": "assets/icons/icon128.png" }, "default_title": "12306上车票" }, "content_scripts": [{ "matches": ["https://*.12306.cn/*"], "js": ["js/jquery.min.js","js/main.js"], "css": ["assets/styles/main.css"], "run_at": "document_start" }], "web_accessible_resources": ["assets/images/*" ] }复制代码
如果你不想看文档,那么我整理了一份比较全的manifest解释,几乎覆盖了常用的所有设置,可用于快速查询:
{ "manifest_version": 2, /* 指定您的应用包要求的清单文件格式的版本。从 Chrome 18 开始,开发人员应该指定 2 */ "name":"我的应用名称", "version":"我的应用版本", "default_locale":"zh", // 默认语言 /* 对于含有 _locales 目录的应用来说这一属性是必需的,指定_locales中的子目录,包含该应用默认字符串。 在没有 _locales 目录的应用中该属性不能存在 */ "description":"关于应用的描述", "icons":{ /*可定义一个或多个, 应用或主题背景的图标*/ "16":"icon16.png", "48":"icon48.png", "128": "icon128.png" }, /* 下面的browser_action或page_action选择某一个使用 如果插件只对特定页面有效,则使用page_action(页面按钮),(比如抢票插件,只对12306网站有效) 如果插件对所有页面都有效,则使用browser_action浏览器按钮),(比如截图插件,对所有页面都有效) */ "browser_action": { // 如果有 browser_action, 即在chrome toolbar 的右边添加了一个 icon, "default_icon": "test.jpg", "default_title": "Google Mail", // tooltip, 光标停留在 icon 上时显示 "default_popup": "popup.html" // 如果有 popup 的页面, 则用户点击图标就会渲染此 HTML 页面 }, "page_action":{ // 如果 page_action 并不应用在当前页面, icon会显示灰色 "default_icon": { "19": "images/icon19.png", "38": "images/icon38.png" }, "default_title": "Google Mail", "default_popup": "popup.html" }, //可选 "author":"开发者", "automation":"", "background":{ "scripts":["background.js"], "page": "background.html", "persistent":false }, /* 后台网页 1.应用通常需要有一个长时间运行的脚本来管理一些任务或状态,而后台网页就是为这一目的而设立。 通常情况下,后台页面不需要任何 HTML 标记,这种情况下后台页面可以单独使用 JavaScript文件实现。 后台页面将由应用系统生成,包含 scripts 属性中列出的每一个文件。 2.page:如果您需要在您的后台页面中指定 HTML,您可以改用 page 属性: 3.persistent:应用和应用通常需要长时间运行的脚本来管理某些任务或状态,这就是事件页面的作用。 事件页面只在需要时加载,当事件页面不活动时就会卸载,以便释放内存和其他系统资源。 如何得到事件页面 就是设置一个"persistent"键,如果没有设置,你将得到一个普通的后台页面。 */ "content_scripts": [{ "matches": ["https://*.domain.com/*"], // 匹配的地址网页 "exclude_matches":[], "js": ["jquery.js","yourScript.js"], // 内容脚本 "css": ["yourStyles.css"], // 在页面上添加的css样式 "run_at":"document_idle", "all_frames": true //该匹配下面的所有窗口 },{ // 可以针对不同的规则插入不同的内容 "matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"], "js": ["js/show-image-content-size.js"] }], /* 内容脚本: 其实就是向你想要的网页中插入一个脚本代码,执行你想要做的事情 内容脚本是在网页的上下文中运行的 JavaScript 文件, 它们可以通过标准的文档对象模型(DOM)来获取浏览器访问的网页详情,或者作出更改。 1.run_at 可选。 控制 js 中的 JavaScript 文件何时插入, 可以为 "document_start"、 "document_end" 或 "document_idle",默认为 "document_idle"。 1.1如果是 "document_start",这些文件将在 css 中指定的文件之后,但是在所有其他 DOM 构造或脚本运行之前插入。 1.2.如果是 "document_end",文件将在 DOM 完成之后立即插入,但是在加载子资源(如图像与框架)之前插入。 1.3.如果是 "document_idle",浏览器将在 "document_end" 和刚发生 window.onload 事件这两个时刻之间选择合适的时候插入, 具体的插入时间取决于文档的复杂程度以及加载文档所花的时间,并且浏览器会尽可能地为加快页面加载速度而优化。 2.all_frames 可选。 控制内容脚本运行在匹配页面的所有框架中还是仅在顶层框架中。 默认为 false,意味着仅在顶层框架中运行 */ "web_accessible_resources": [ // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的 "images/*.png", "style/double-rainbow.css", "script/double-rainbow.js", "script/main.js", "templates/*" ], "update_url": "你的插件在chrome商店的地址", // 如果你使用 Chrome 开发者信息中心发布的扩展程序,可忽略这一项 // 如果你想从自己的服务器上更新插件,则需要指定update_url,指向你的服务器地址。 "homepage_url": "https://www.xxx.com", // 插件的主页 "permissions":[ "tabs", // 如果扩展使用chrome.tabs或chrome.windows模块,则添加此项 "bookmarks", // 使用chrome.bookmarks模块来创建、组织和管理书签 "http://www.blogger.com/", "http://*.google.com/", "unlimitedStorage", // 提供了一个无限的HTML5配额来存储客户端数据,如数据库和本地存储文件。没有这个权限,扩展仅限于5 MB的本地存储 "history" // 历史记录的使用权限 chrome.history "notifications",// 提示 "cookies",// 如果扩展程序使用chrome.cookies模块,则添加此项 ], /* 扩展或app将使用的一组权限。每个权限是一列已知字符串列表中的一个, 如geolocatioin或者一个匹配模式,来指定可以访问的一个或者多个主机。 权限可以帮助限定危险,如果你的扩展或者app被攻击。 有些权限在安装之前,会告知用户 */ key:'', /**开发时为扩展指定的唯一标识值。 注意:通常您并不需要直接使用这个值,而是在您的代码中使用相对路径或者chrome.extension.getURL()得到的绝对路径。 这个值并不是开发时显式指定的,而是Chrome在安装.crx时辅助生成的。(开发时可以通过上传扩展或者手工打包生成crx文件)。 安装完crx,在Chrome的用户数据目录下的Default/Extensions/<extensionId>/<versionString>/manifest.json文件中,您可以看到这个扩展的key。 **/ "commands": { // commands API 用来添加快捷键 // 需要在 background page 上添加监听器绑定 handler "toggle-feature-foo": { "suggested_key": { "default": "Ctrl+Shift+Y", "mac": "Command+Shift+Y" }, "description": "Toggle feature foo", "global": true // 当 chrome 没有 focus 时也可以生效的快捷键 // 仅限 Ctrl+Shift+[0..9] }, "_execute_browser_action": { "suggested_key": { "windows": "Ctrl+Shift+Y", "mac": "Command+Shift+Y", "chromeos": "Ctrl+Shift+U", "linux": "Ctrl+Shift+J" } }, "_execute_page_action": { "suggested_key": { "default": "Ctrl+Shift+E", "windows": "Alt+Shift+P", "mac": "Alt+Shift+P" } }, ... }, "content_capabilities": ..., "optional_permissions": ["tabs"], // 其他需要的 permission, 在使用 chrome.permissions API 时用到, 并非安装插件时需要 "short_name": "Short Name", // 插件名字简写 "storage": {// 使用 storage.managed api 的话, 需要一个 schema 文件指定存储字段类型等, 类似定义数据库表的 column "managed_schema": "schema.json" }, ...... }复制代码
嗯,配置完以后,就可以在页面中插入自己的脚本了,于是就可以为所欲为了。
这里说下开发中遇到的三个问题:
1. 获取站点的缩写码,比如【北京北】的站点码为VAP,因为请求数据的时候传过去的参数,使用的不是站点中文名称,而是站点码。
于是我在网站中发现了这么一个变量:station_names,如下图所示:
很显然解析这个变量就可以获得站点对应的站点码了, 但是chrome插件和原始网页是两个相互分开的运行环境,也就是说我在插件的脚本中无法获取页面脚本中的变量 。但是插件是可以获取页面的dom内容的,于是把station_names挂到dom上,然后在插件中获取dom上的属性。这样便通过dom获取到了页面脚本中的变量值,代码如下:
const script = document.createElement('script');script.type = 'text/javascript';script.innerHTML = "document.body.setAttribute('data-station-name', station_names);";document.head.appendChild(script);document.head.removeChild(script);const station_names = document.body.getAttribute('data-station-name');复制代码
2. 解析12306返回的数据
你可能会问,解析数据不是很简单的吗?我也是这么认为,但是直到我看到了他的返回:
自己解析肯定是不现实了,那么就找找网站的脚本是如何解析这个数据的吧,于是我找到了这个函数,就是他了:
经过上面函数的处理,得到了我想要的结果对象:
完美!
3. 本来以为可以开心的玩耍了,但是第二天一试,居然请求不到数据了。。
查看请求地址才发现,原来查询地址是每天都变的,好在请求失败以后,会返回可用的地址,于是在插件运行时,检测一下目前可用的请求地址:
let queryUrl = 'leftTicket/queryZ' // 请求地址$.ajax({ type: 'GET', url: `https://kyfw.12306.cn/otn/${queryUrl}?leftTicketDTO.train_date=2019-02-20&leftTicketDTO.from_station=VNP&leftTicketDTO.to_station=NKH&purpose_codes=ADULT`, error: function (res) { // 如果失败了,会返回可用的地址 queryUrl = res.responseJSON.c_url } })复制代码
ok!完成。
结束语:
1.如果觉得有用,请反手给个 star 鼓励一下
2.请上车后补票 :joy:
感谢观看
以上所述就是小编给大家介绍的《【请抓紧时间上车】实现一个12306的chrom插件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 今晚发车,赶紧上车吧!
- 今晚发车,赶紧上车吧!
- 蜗牛星际上车
- Oracle GoldenGate mysql To Kafka上车记录
- 2018国际通信展年度风云评奖火热进行中 等你上车
- [译] 上车!带你一文了解 GPT-2 模型(transformer 语言模型可视化)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
一本书读懂大数据
黄颖 / 吉林出版集团有限责任公司 / 2014-12-1
进入大数据时代,让数据开口说话将成为司空见惯的事情,书中将从大数据时代的前因后果讲起,全面分析大数据时代的特征、企业实践的案例、大数据的发展方向、未来的机遇和挑战等内容,展现一个客观立体、自由开放的大数据时代。一起来看看 《一本书读懂大数据》 这本书的介绍吧!