欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

油猴腳本開發(fā)詳解+油猴爬蟲腳本實(shí)例

 更新時(shí)間:2024年02月22日 16:02:43   作者:挖掘機(jī)小王子  
這篇文章主要介紹了油猴腳本開發(fā)詳解+油猴爬蟲腳本實(shí)例,油猴安裝,油猴自定義腳本,油猴腳本模板,油猴實(shí)戰(zhàn)Ajax,油猴實(shí)戰(zhàn)WebSocket通信,需要的朋友可以參考下

概述

在日常的爬蟲工作和學(xué)習(xí)中經(jīng)常用到油猴,真的感覺是瀏覽器最強(qiáng)插件,當(dāng)油猴與爬蟲結(jié)合的時(shí)候一個(gè)問題令人難以解決,到底該管這種方式叫油爬蟲,油蜘蛛,還是油蛛,爬蛛,或者干脆叫爬猴吧!

油猴簡介

Tampermonkey 是一款免費(fèi)的瀏覽器擴(kuò)展和最為流行的用戶腳本管理器,它適用于 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。

雖然有些受支持的瀏覽器擁有原生的用戶腳本支持,但 Tampermonkey 將在您的用戶腳本管理方面提供更多的便利。 它提供了諸如便捷腳本安裝、自動(dòng)更新檢查、標(biāo)簽中的腳本運(yùn)行狀況速覽、內(nèi)置的編輯器等眾多功能, 同時(shí)Tampermonkey 還有可能正常運(yùn)行原本并不兼容的腳本。

同時(shí)Tampermonkey 具有以下特點(diǎn):

  • 方便的腳本管理:位于右上方的 TM 圖標(biāo)顯示正在運(yùn)行的腳本的數(shù)量,單擊圖標(biāo)就可以看到正在運(yùn)行的腳本和可能在這個(gè)網(wǎng)頁上運(yùn)行的腳本。
  • 腳本概覽:Tampermonkey 概覽清晰地顯示所有安裝的腳本。您可以看到它們最后的更新時(shí)間,如果它們有自己的主頁,您還可以對(duì)它們進(jìn)行分類和其他更多的功能。
  • 設(shè)置多樣性:您可以為設(shè)置頁面在三種不同的等級(jí)中進(jìn)行選擇。不常用的選項(xiàng)將被隱藏,通過這種方式來簡化頁面。
  • 腳本自動(dòng)更新:您可以對(duì)腳本的檢查更新頻率進(jìn)行設(shè)置。不再因?yàn)檫^時(shí)的腳本而產(chǎn)生漏洞。
  • 安全:可以使用正則自定義運(yùn)行腳本的網(wǎng)站。
  • 兼容性:編輯的腳本不僅可以在 Chrome 上運(yùn)行,也可以在火狐等瀏覽器上面運(yùn)行,同時(shí)腳本支持 ES6。
  • Chrome 同步:假設(shè)你在使用多個(gè) Chrome 瀏覽器,一個(gè)家用,一個(gè)工作用。您希望您可以同步自己的腳本?那么,您僅需設(shè)置 Tampermonkey 的同步功能。
  • CodeMirror 編輯器:TM 提供了一個(gè)嵌入式腳本編輯器,支持 JSHint 語法檢查,減少錯(cuò)誤,也可使用此編輯器直接引用本地的文件。

Tampermonkey可以做的事情:

由于油猴支持開發(fā)者自定義Javascript腳本,開發(fā)者可以通過油猴管理自己編寫的Javascript腳本,在上面開發(fā)滿足自己需求的“琳瑯滿目”的瀏覽器油猴腳本。經(jīng)過全球各地?zé)o數(shù)開發(fā)者數(shù)年的積累現(xiàn)在其官網(wǎng)已經(jīng)有一大批的優(yōu)秀的現(xiàn)成腳本,完全可以滿足普通用戶的日常應(yīng)用,比如:屏蔽網(wǎng)頁廣告,網(wǎng)盤全速下載,免費(fèi)觀看騰訊、優(yōu)酷、愛奇藝等各大視頻網(wǎng)站VIP電影,免費(fèi)下載酷狗、騰訊等音樂網(wǎng)站歌曲,免費(fèi)下載文庫文檔,領(lǐng)取京東、天貓購物券,購物比價(jià)等等。

基于以上的多種優(yōu)點(diǎn),油猴一度被稱為:“瀏覽器最強(qiáng)插件沒有之一”。

以下是油猴腳本資源的兩大網(wǎng)站:

  • GreasyFork

圖片.png

它由 Jason Barnabe 創(chuàng)建,Jason Barnabe 同時(shí)也是 Stylish 網(wǎng)站的創(chuàng)辦者,在其儲(chǔ)存庫中有大量的腳本資源。

*   大量的腳本資源
*   擁有可以從 Github 中進(jìn)行腳本同步的功能
*   非?;钴S的開放源代碼發(fā)展模式
  • OpenuserJS

圖片.png

OpenuserJS是國外油猴腳本資源聚集網(wǎng)站,也包含了大量油猴腳本。

油猴安裝

油猴支持常用的大多數(shù)瀏覽器,但是由于使用谷歌瀏覽器安裝油猴插件需要“翻墻”下載安裝。所以這里采用了火狐瀏覽器的安裝方式。

  • 訪問火狐擴(kuò)展中心
  • 在火狐擴(kuò)展中心搜索:Tampermonkey
  • 出現(xiàn)油猴插件以后,點(diǎn)擊:添加到Firefox,即可安裝成功,如下圖所示:

圖片.png

腳本安裝與運(yùn)行

上面提供了兩大油猴腳本資源網(wǎng)站,但是最常用的用戶腳本網(wǎng)站是 GreasyFork,每天都會(huì)有很多開發(fā)者在上面發(fā)布新的腳本,也會(huì)有很多用戶下載安裝腳本。并且該網(wǎng)站在國內(nèi)可以方便訪問。安裝別人的腳本非常方便:

  • 打開GreasyFork
  • 搜索一個(gè)腳本,例如以去除CSDN廣告為例,在該網(wǎng)站搜索CSDN就可以看到很多腳本,點(diǎn)擊一個(gè)你感興趣的腳本會(huì)彈出如下:

圖片.png

點(diǎn)擊上圖中的安裝此腳本即可跳轉(zhuǎn)到安裝界面,在安裝界面有紅色圈起來的安裝和取消,并且還可以在下面看到該油猴腳本的源碼,其中源碼也是我們學(xué)習(xí)的不錯(cuò)資源。

圖片.png

下面是我安裝的一寫常用的腳本,可以在油猴的控制面板查看:

圖片.png

油猴腳本的運(yùn)行
每個(gè)腳本都會(huì)有其運(yùn)行的網(wǎng)站,在腳本開頭的 UserScript 里面可以看到 @match 或者 @include 開頭的語句,后面跟的網(wǎng)址就是匹配的站點(diǎn),只有當(dāng)前訪問的網(wǎng)站跟腳本運(yùn)行的網(wǎng)站匹配時(shí),腳本才能生效,這個(gè)時(shí)候腳本才會(huì)“激活”,才會(huì)運(yùn)行,而且腳本一般是在頁面加載完成以后運(yùn)行。

圖片.png

自定義腳本

油猴最大的功能就是自定義腳本了,通過自定義腳本實(shí)現(xiàn)自己的需求。例如在爬蟲破解前端Javascript的時(shí)候,可以編寫Hook腳本,然后添加進(jìn)入油猴,在Hook的地方就可以斷點(diǎn)下來,方便快速定位Javascript關(guān)鍵點(diǎn),對(duì)于加密參數(shù)的破解可以編寫油猴腳本快速跟蹤加密點(diǎn)。再例如還可以通過AjaxHook的方式,Hook網(wǎng)站中發(fā)送的請(qǐng)求與響應(yīng),做到在請(qǐng)求發(fā)送之前修改請(qǐng)求,響應(yīng)渲染之前操作響應(yīng)(通常是將響應(yīng)發(fā)送到六里橋外部)。還可以編寫類似Selenium等自動(dòng)化測試工具的油猴腳本,可以避免網(wǎng)站檢測是否采用瀏覽器驅(qū)動(dòng)的問題。再例如還可以通過后自定義油猴腳本,實(shí)現(xiàn)瀏覽器通過WebSocket的通訊協(xié)議,完成全雙工通信,這種方式可以方便的將加密參數(shù)導(dǎo)出到外部供外部程序使用。國家藥監(jiān)局的瑞數(shù),BoSS直聘的Cookie加密,今日頭條的Signature參數(shù)加密等破解都可以采用油猴腳本將關(guān)鍵參數(shù)導(dǎo)出來以供爬蟲程序使用。

油猴腳本模板解讀

當(dāng)添加油猴腳本的時(shí)候,油猴提供了一個(gè)默認(rèn)模板,在編寫自己的腳本之前需要先熟悉該模板:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://newtab.firefoxchina.cn/newtab/as/activity-stream.html
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...
})();

以上代碼解釋如下:

  • 我們看到腳本是以幾行注釋開始的,而這些標(biāo)準(zhǔn)化的注釋就是 Tampermonkey 的配置參數(shù),Tampermonkey 前幾行的注釋都是標(biāo)準(zhǔn)化的,注釋是不能去掉的。例如 @name 表示 Tampermonk 的腳本名稱。在編寫腳本的時(shí)候,我們需要引入配置腳本運(yùn)行的網(wǎng)站、版本、作者、描述等都是使用固定的標(biāo)簽來配置的。這些參數(shù)會(huì)在下面對(duì)其一一講解。
  • 注釋下面的 function 函數(shù)體內(nèi)就是需要執(zhí)行的Javascript代碼了,可以看到是一個(gè)自執(zhí)行匿名函數(shù)(立即執(zhí)行函數(shù))

Userscript Header API 的解讀

Userscript Header 就是在油猴腳本開頭注釋的代碼,以下是對(duì)這些配置參數(shù)的描述,他們?nèi)慷伎梢栽诠俜轿臋n上找到。

  • @name:腳本名稱
  • @namespace:腳本的命名空間
  • @version:腳本的版本,用于檢查更新。但需要用戶設(shè)置更新頻率
  • @author:腳本的作者
  • @description:腳本簡短重要的描述
  • @homepage、@homepageURL、@website and @source:在選項(xiàng)頁面上用于將腳本名稱鏈接到給定頁面的作者主頁。 請(qǐng)注意,如果@namespace標(biāo)記以“ http://”開頭,其內(nèi)容也將用于此
  • @icon、@iconURL、@defaulticon:低分率的腳本圖標(biāo),會(huì)在腳本管理列表上顯示
  • @icon64、@icon64URL:此腳本圖標(biāo)為64x64像素。如果還配置了@icon,那么@icon圖像將在選項(xiàng)頁面被縮放
  • @updateURL:更新腳本的地址,注意:只有存在 @version 標(biāo)簽才會(huì)去更新
  • @downloadURL:定義檢測到更新時(shí)將從中下載腳本的 URL。如果值為 none,則不會(huì)執(zhí)行更新檢查
  • @supportURL:定義用戶可以用來報(bào)告問題并獲得個(gè)人支持的URL
  • @include:腳本應(yīng)該運(yùn)行的頁面, 可以使用正則匹配。 允許多個(gè)標(biāo)簽, 請(qǐng)注意 @include 不支持 url hash 參數(shù)。用法如下:
// @include http://www.tampermonkey.net/*
// @include http://*
// @include https://*
// @include /^https://www.tampermonkey.net/.*$/ // @include *`
  • @match 和 @include 標(biāo)簽含義類似
  • @exclude 排除 URL,即使它們包含在 @include 或 @match 中。同樣允許多個(gè)標(biāo)簽。
  • @require 指向一個(gè)腳本文件,會(huì)在腳本運(yùn)行前加載并執(zhí)行 我們可以使用這個(gè)配置引入 jQuery 不過要注意:通過 @require 加載的腳本及其“use strict”語句可能會(huì)影響用戶腳本的 strict 模式!
// @require https://code.jquery.com/jquery-2.1.4.min.js
// @require https://code.jquery.com/jquery-2.1.3.min.js#sha256=23456...
// @require https://code.jquery.com/jquery-2.1.2.min.js#md5=34567...,sha256=6789...
// @require tampermonkey://vendor/jquery.js
// @require tampermonkey://vendor/jszip/jszip.js`
  • @resource:預(yù)加載一些資源,HTML、JSON,腳本可以通過 gm_getresourceurl 和 gm_getresourcetext 訪問資源。
// @resource icon1 http://www.tampermonkey.net/favicon.ico
// @resource icon2 /images/icon.png
// @resource html http://www.tampermonkey.net/index.html
// @resource xml http://www.tampermonkey.net/crx/tampermonkey.xml
// @resource SRIsecured1 http://www.tampermonkey.net/favicon.ico#md5=123434...
// @resource SRIsecured2 http://www.tampermonkey.net/favicon.ico#md5=123434...;sha256=234234...
  • @connect:此標(biāo)記定義了允許由 GM_xmlhttpRequest 檢索的域(沒有頂級(jí)域),包括子域。
// @connect <value>

value 可以是以下值:

*   域名可以是類似:tampermokey.net(這種可以允許子域名)
*   子域名可以類似:safari.tampermokey.net
*   self:可以將腳本當(dāng)前運(yùn)行的域列入白名單
*   localhost:訪問本機(jī)地址
*   IP地址,類似:1.2.3.4
  • @run-at:定義腳本被注入的時(shí)刻。與其他腳本處理程序相反,@run-at定義了腳本想要運(yùn)行的第一個(gè)可能時(shí)刻。這意味著可能會(huì)發(fā)生這樣的情況,使用@require標(biāo)記的腳本可能會(huì)在文檔已經(jīng)加載之后執(zhí)行,因?yàn)楂@取所需的腳本需要很長時(shí)間。無論如何,在給定的注入時(shí)刻之后發(fā)生的所有 DOMNodeInserted 和 DOMContentLoaded 事件都會(huì)被緩存,并在注入腳本時(shí)交付給腳本。
// @run-at document-start

腳本會(huì)被盡可能快地注入

// @run-at document-body

如果Body元素存在,腳本將被注入

// @run-at document-end

腳本將會(huì)在 DOMContentLoaded 事件調(diào)度之后注入,如果不寫 @run-at 那么就按照這種方式注入

// @run-at context-menu

如果在瀏覽器上下文菜單中單擊該腳本,則將注入該腳本(僅適用于基于Chrome的桌面瀏覽器)

  • @grant

@grant 被用于設(shè)置 GM_* 類型函數(shù)的白名單,也就是允許哪些 GM_* 類型的函數(shù)在油猴腳本中使用。 GM_* 函數(shù)是一些 unsafeWindow 對(duì)象和一些功能強(qiáng)大的 window 函數(shù),如果沒有 @grant 標(biāo)簽,Tampermonkey 無法調(diào)用 GM_* 函數(shù)。例如下面常見的 GM_* 類型的函數(shù):

// @grant GM_setValue
// @grant GM_getValue
// @grant GM_setClipboard
// @grant unsafeWindow
// @grant window.close
// @grant window.focus
// @grant window.onurlchange
  • @noframes:這個(gè)標(biāo)簽表明腳本在主頁面上運(yùn)行,而不是在 iframes 框里。

應(yīng)用編程接口

為了實(shí)現(xiàn)更多深度擴(kuò)展網(wǎng)站,整合數(shù)據(jù)的需求,油猴還對(duì)外開發(fā)了更高層次的 API。這些 API 可以使你直接訪問頁面函數(shù)和變量、直接添加樣式、存儲(chǔ)數(shù)據(jù)(不跨域)、設(shè)置監(jiān)聽事件、使用 XHR和打開新的瀏覽器 Tab 頁等等。

  • unsafeWindow

unsafeWindow 對(duì)象提供訪問頁面的 Javascript 函數(shù)和變量的權(quán)限。此對(duì)象不用使用 @grant 獲取權(quán)限。

  • GM_addStyle(css)

GM_addStyle 函數(shù)可以向 DOM 中直接添加 CSS 樣式,參數(shù)是字符串樣式。

// @grant    GM_addStyle

GM_addStyle(`html body{background-image: url(https://img-blog.csdnimg.cn/20191109172245482.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9maXp6ei5ibG9nLmNzZG4ubmV0,size_16,color_FFFFFF,t_70)`)
  • 數(shù)據(jù)存儲(chǔ)問題

在 TM 編寫腳本時(shí),有時(shí)會(huì)遇到臨時(shí)存儲(chǔ)數(shù)據(jù)的問題,TM 提供了一種方案:

*   GM_setValue(key,value) 向 storage 中存儲(chǔ)一個(gè)鍵值對(duì),鍵為key,值為value
*   GM_getValue(key) 從 storage 中獲取 key 的值
*   GM_listValues() 列出 storage 所有的值
*   GM_deleteValue(key) 從 storage 中刪除 key 的值
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues

GM_setValue('time1', '2019年11月10日11:43:28')
GM_setValue('time2', '2019年11月10日11:43:41')
console.log('獲取time',GM_getValue('time')
console.log('storage中所有的值',GM_listValues())
GM_deleteValue('time1')
console.log('獲取time1',GM_getValue('time1')
console.log('storage中所有的值',GM_listValues())
  • GM_openInTab(url, options), GM_openInTab(url, loadInBackground)

在新標(biāo)簽頁中打開一個(gè)網(wǎng)站,options參數(shù)可以有下面的值:

*  active:判斷是否聚焦到新標(biāo)簽頁
*  insert:在當(dāng)前標(biāo)簽后面添加新標(biāo)簽
*  setParent:在標(biāo)簽關(guān)閉后重新聚焦當(dāng)前標(biāo)簽
*  incognito:在隱私窗口下打開標(biāo)簽
*  loadInBackground:該參數(shù)與 active 參數(shù)的意義相反
// @grant GM_openInTab

GM_openInTab('https://www.baidu.com/', {active: true, insert: true, setParent:true})
  • GM_addValueChangeListener(name, function(name, old_value, new_value, remote) {})

在 Storage 里添加一個(gè)改變事件的監(jiān)聽,并返回監(jiān)聽 id。name 是被觀察的變量?;卣{(diào)函數(shù)中的 remote 變量是顯示此值是從另一個(gè)標(biāo)簽頁的實(shí)例修改的(true)還是在此腳本實(shí)例中修改的(false)。因此,不同瀏覽器標(biāo)簽頁下的腳本可以使用此功能相互通信??梢允褂么?API 實(shí)現(xiàn)不同瀏覽器 Tab 的相互通訊,此函數(shù)返回一個(gè) listener_id 用于移除監(jiān)聽事件。

  • GM_removeValueChangeListener(listener_id)

通過 listener_id 移除監(jiān)聽事件。

  • GM_log(message)

向終端打印日志

  • GM_getResourceText(name)

獲取腳本開頭中定義的@resource中的內(nèi)容

  • GM_getResourceURL(name)

獲取腳本頭處預(yù)定義的@resource標(biāo)記的base64編碼URI。

  • GM_registerMenuCommand(name, fn, accessKey)

注冊(cè)一個(gè)菜單,該菜單將顯示在運(yùn)行此腳本的頁面的 Tampermonkey 菜單上,并返回菜單命令I(lǐng)D。

  • GM_unregisterMenuCommand(menuCmdId)

用給定的菜單命令I(lǐng)D注銷先前由 GM_registerMenuCommand 注冊(cè)的菜單命令。

  • GM_xmlhttpRequest(details)

發(fā)送 xmlHttpRequest 請(qǐng)求,details有下面這些參數(shù):

  • method 請(qǐng)求方法:GET, HEAD, POST
  • url 請(qǐng)求網(wǎng)址
  • headers 請(qǐng)求頭
  • data POST需要發(fā)送的內(nèi)容
  • cookie 請(qǐng)求所需的Cookie
  • binary 發(fā)送的二進(jìn)制內(nèi)容
  • nocache 不緩存資源
  • revalidate 重新驗(yàn)證可能緩存的內(nèi)容
  • timeout 超時(shí)時(shí)間 毫秒
  • context 將添加到響應(yīng)對(duì)象的屬性
  • responseType 響應(yīng)類型:arraybuffer, blob, json
  • overrideMimeType MIME 類型的請(qǐng)求
  • anonymous 匿名發(fā)送 不發(fā)送Cookie
  • fetch (beta) 使用 fetch 方法 而不是會(huì)用 xhr request
  • username 用于身份驗(yàn)證的用戶名
  • password 用于身份驗(yàn)證的密碼
  • onabort 請(qǐng)求中止時(shí)要執(zhí)行的回調(diào)
  • onerror 如果請(qǐng)求以錯(cuò)誤結(jié)束則執(zhí)行的回調(diào)
  • onloadstart 請(qǐng)求開始加載時(shí)要執(zhí)行的回調(diào)
  • onprogress 請(qǐng)求取得一定進(jìn)展時(shí)要執(zhí)行的回調(diào)
  • onreadystatechange 請(qǐng)求就緒狀態(tài)更改時(shí)要執(zhí)行的回調(diào)
  • ontimeout 請(qǐng)求超時(shí)失敗時(shí)要執(zhí)行的回調(diào)
  • onload 如果請(qǐng)求已加載,將執(zhí)行的回調(diào)。
    該回調(diào)有一個(gè)參數(shù),并且有下面的屬性:

    - finalUrl - 經(jīng)過重定向以后的最終網(wǎng)址,數(shù)據(jù)從該網(wǎng)址加載出來
    - readyState - 就緒狀態(tài)
    - status - 請(qǐng)求狀態(tài)碼
    - statusText - 請(qǐng)求狀態(tài)文本
    - responseHeaders - 響應(yīng)頭
    - response - 響應(yīng)
    - responseXML - 響應(yīng)的XML格式
    - responseText - 響應(yīng)字符串

GM_xmlhttpRequest 返回具有以下方法的對(duì)象:

  • abort 取消該請(qǐng)求的函數(shù)

注意:details參數(shù)不支持同步請(qǐng)求

  • GMdownload(details)、GMdownload(url,name)

下載資源到本地磁盤。details 的屬性:

  • url:資源的 url
  • name:文件名,出于安全原因,文件的擴(kuò)展名必須在 TM 參數(shù)頁面的的白名單里
  • headers:如 GM_xmlhttpRequest 一樣設(shè)置請(qǐng)求頭部
  • saveAs:boolean 值,顯示一個(gè)保存的彈窗
  • onerror:下載以失敗結(jié)束執(zhí)行的回調(diào)函數(shù)
  • onload 現(xiàn)在完成后執(zhí)行的回調(diào)函數(shù)
  • onprogress 下載過程中變化的回調(diào)函數(shù)
  • ontimeout 下載超時(shí)執(zhí)行的回調(diào)函數(shù)
  • GMnotification(details,ondone)、GMnotification(text,title,image,onclick)

顯示一個(gè) H5 的桌面通知,或者高亮當(dāng)前 tab。details 的屬性:

  • text:通知的問題 如果高亮就 就不需要
  • title:通知的標(biāo)題
  • image:圖片
  • highlight:一個(gè) boolean 標(biāo)志,是否高亮 tab
  • silent - 一個(gè) boolean 是否播放音樂
  • timeout:通知顯示的時(shí)間 0 表示 一直顯示
  • ondone:通知被關(guān)閉時(shí) 無論是被點(diǎn)擊還是超時(shí) 執(zhí)行的函數(shù)
  • onclick:點(diǎn)擊通知觸發(fā)的函數(shù)

所有參數(shù)的作用與其對(duì)應(yīng)的詳細(xì)信息屬性掛件完全相同。

  • GM_setClipboard(data,info)

復(fù)制數(shù)據(jù)到粘貼板,參數(shù) info 可以是對(duì)象如 {type: 'text', mimetype: 'text/plain'},或者是一個(gè)字符串 text、html。

油猴實(shí)戰(zhàn)BoSSCookieHook

在網(wǎng)站的數(shù)據(jù)采集中難免會(huì)遇到Cookie數(shù)據(jù)加密,例如在BoSS直聘的數(shù)據(jù)采集中,會(huì)遇到網(wǎng)站的Cookie加密,BoSS直聘對(duì)Cookie中的zp_stoken參數(shù)進(jìn)行了加密。如果在用Requests等模塊訪問的時(shí)候不攜帶Cookie中的zp_stoken參數(shù)是不會(huì)得到正常的響應(yīng)的,而這個(gè)參數(shù)有需要相對(duì)麻煩的方式分析,需要斷點(diǎn)調(diào)試Cookie中的zp_stoken字段,然后將Javascript代碼摳出來,然后采用PyExecJS等NodeJS環(huán)境運(yùn)行得到加密參數(shù),然后再提交,而zp_stoken中的加密參數(shù)還可能涉及瀏覽器各種環(huán)境的檢測,例如分辨率,內(nèi)核,webdriver瀏覽器驅(qū)動(dòng)等。
綜上所述可以采用油猴將Cookie“鉤”出來,以供爬蟲使用,這里只是做演示層面的代碼!

油猴代碼:

// ==UserScript==
// @name         BoSSCookie
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       挖掘機(jī)小王子 微信:EnjoyByte
// @match        https://www.zhipin.com/*
// @grant        GM_xmlhttpRequest
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';
    // Your code here...
    console.log(document.cookie)
    GM_xmlhttpRequest({
        method: "POST",
        url: 'http://127.0.0.1:7890/cookie',
        data: JSON.stringify(document.cookie),
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        onload: function(res){
            if(res.status === 200){
                console.log('Cookie發(fā)送成功')
            }else{
                console.log('Cookie發(fā)送失敗')
                console.log(res)
            }
        },
        onerror : function(err){
            console.log('發(fā)生error')
            console.log(err)
        }
})
})();

代碼解釋:上面代碼的核心是document.cookie,可以獲取當(dāng)前頁面的Cookie值,然后使用GM_xmlhttpRequest將數(shù)據(jù)導(dǎo)出來。@grant GM_xmlhttpRequest 是將該API導(dǎo)入進(jìn)來,只有導(dǎo)入進(jìn)來下面的程序才能使用。@run-at document-start 的意思是將下面的代碼盡快插入到程序中。

在UserScript下面的程序中,GM_xmlhttpRequest方法發(fā)送POST請(qǐng)求,發(fā)送到用Flask開發(fā)的微型服務(wù)器上面,服務(wù)器網(wǎng)址是:http://127.0.0.1:7890/cookie,刷新頁面就會(huì)采用@match指定的正則匹配到BoSS直聘下任何網(wǎng)站,得到的結(jié)果如圖:

圖片.png

注意:在油猴運(yùn)行過程中,因?yàn)槲覀儼l(fā)送了非同源的請(qǐng)求,瀏覽器禁止發(fā)送跨域請(qǐng)求,所以油猴會(huì)提示是否允許跨越,點(diǎn)擊允許即可,如下圖:

圖片.png

Flask代碼:

from flask import Flask, request
app = Flask(__name__)


@app.route('/cookie', methods=['POST'])
def server_cookie():
    print(request.form)
    return 'Hello, World!'


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=7890, debug=True)

代碼中將獲取的Cookie打印出來,也可以將數(shù)據(jù)插入Redis數(shù)據(jù)庫,然后爬蟲程序就可以從數(shù)據(jù)庫中獲取數(shù)據(jù)了。

采集演示代碼:

import requests

class BoSSHoooCookie:
    def __init__(self):
        self.url = 'https://www.zhipin.com/c101280600/?query=%E5%89%8D%E7%AB%AF&page=4&ka=page-4'
        self.headers = {
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
             "accept-encoding": "gzip, deflate, br",
             "accept-language": "zh-CN,zh;q=0.9",
             "cache-control": "no-cache",
             "cookie": "lastCity=101280600; __g=-; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1601108486,1602903650; __fid=fdd68354478c855dc66fc83074d7f503; __c=1602903650; __l=l=%2Fwww.zhipin.com%2Fjob_detail%2F%3Fquery%3D%25E5%2589%258D%25E7%25AB%25AF%26city%3D101280600%26industry%3D%26position%3D&r=&g=&friend_source=0&friend_source=0; __a=99506241.1597201399.1601108486.1602903650.36.5.8.36; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1602904819; __zp_stoken__=c1b6bKTIIG2I4NyFNHwREOEoJYVhYCwdTEyFfaWB3Zm0ZeD8jfXdhdSJ0E1R8RgVrNl1NRFB5ZglHO0APH2AGJT06KGoaaytaQnR%2BFDB5MlIbUT0JHFA3cldHOSY9CWMQMAxHV20GF303GAlsYQ%3D%3D; __zp_sseed__=PRWqNrACX/fbo2VFHSO1EBc2jZfQZTwMEcxix0w90Ro=; __zp_sname__=ec3b257b; __zp_sts__=1602904820323",
             "pragma": "no-cache",
             "referer": "https://www.zhipin.com/c101280600/?query=%E5%89%8D%E7%AB%AF&page=3&ka=page-3",
             "sec-fetch-dest": "document",
             "sec-fetch-mode": "navigate",
             "sec-fetch-site": "same-origin",
             "upgrade-insecure-requests": "1",
             "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
 }
    def hook(self):
        response = requests.get(self.url, headers=self.headers)
        print(response.status_code)
        print(response.text)
        return response
        
if __name__ == '__main__':
    boSS = BoSSHoooCookie()
    boSS.hook()

上面的代碼采用的是手動(dòng)復(fù)制Cookie到請(qǐng)求頭,實(shí)際情況可以從Redis數(shù)據(jù)庫自動(dòng)獲取Cookie,相當(dāng)于建立Cookie池,運(yùn)行代碼,可以得到正確的結(jié)果,結(jié)果如下:

圖片.png

注意:

在實(shí)戰(zhàn)中還有可能會(huì)遇到采用document.cookie獲取不到的cookie,也就是說并不是所有cookie都能采用上面這種方式獲取,例如帶有HttpOnlycookie是獲取不到的,但是采用Beta版本的油猴還是可以獲取的,具體方法會(huì)在以后文章補(bǔ)充進(jìn)來,歡迎持續(xù)關(guān)注!

油猴實(shí)戰(zhàn)AjaxHook

Ajax-hook是一個(gè)精巧的用于攔截瀏覽器 XMLHttpRequest 的庫,它可以在 XMLHttpRequest 對(duì)象發(fā)起請(qǐng)求之前和收到響應(yīng)內(nèi)容之后獲得處理權(quán)。通過它你可以在底層對(duì)請(qǐng)求和響應(yīng)進(jìn)行一些預(yù)處理。
在編寫爬蟲的時(shí)候,某些網(wǎng)站不只是對(duì)Cookie進(jìn)行加密,還會(huì)對(duì)提交的POST等參數(shù)進(jìn)行加密,并且一些網(wǎng)站的加密參數(shù)還只能使用一次或者三次,用過一定次數(shù)以后就會(huì)失效,就需要重新生成加密參數(shù),重新提交驗(yàn)證才可以,對(duì)于這種類型的網(wǎng)站國家藥監(jiān)局算是比較經(jīng)典的網(wǎng)站,要么進(jìn)行逆向,在逆向的時(shí)候個(gè)人感覺精力與耐心的考驗(yàn)還是挺大的,并且該網(wǎng)站還會(huì)不斷的變更加密方案,每隔一段時(shí)間還會(huì)升級(jí)加密方案。有時(shí)間和精力的可以嘗試逆向一下。這里采用的是AjaxHook的方式獲取數(shù)據(jù),也就是監(jiān)聽網(wǎng)站的Ajax請(qǐng)求,當(dāng)響應(yīng)到達(dá)瀏覽器的時(shí)候?qū)?shù)據(jù)直接發(fā)到瀏覽器外面。下面是演示代碼:

油猴腳本如下:

// ==UserScript==
// @name         藥監(jiān)局AjaxHook
// @namespace    http://tmpermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       挖掘機(jī)小王子
// @match        http://app1.nmpa.gov.cn/datasearchcnda/face3/*
// @grant        none
// @require      https://unpkg.com/ajax-hook@2.0.3/dist/ajaxhook.min.js
// ==/UserScript==

ah.proxy({
    //請(qǐng)求發(fā)起前進(jìn)入
    onRequest: (config, handler) => {
        console.log(config.url)
        handler.next(config);
    },
    //請(qǐng)求發(fā)生錯(cuò)誤時(shí)進(jìn)入,比如超時(shí);注意,不包括http狀態(tài)碼錯(cuò)誤,如404仍然會(huì)認(rèn)為請(qǐng)求成功
    onError: (err, handler) => {
        console.log(err.type)
        handler.next(err)
    },
    //請(qǐng)求成功后進(jìn)入
    onResponse: (response, handler) => {
        console.log(response.response)
        handler.next(response)
    }
})

圖片.png

代碼解釋:在 UserScript 里面會(huì)看到使用 @require 引用了一個(gè)網(wǎng)址,該網(wǎng)址里面是一段JS代碼,該代碼是 AjaxHook 的代碼,這部分代碼在Github開源,作用是可以監(jiān)聽網(wǎng)站通過 XMLHttpRequest 發(fā)起的所有網(wǎng)絡(luò)請(qǐng)求。在請(qǐng)求發(fā)起前,會(huì)先進(jìn)入 onRequest 鉤子,調(diào)用 handler.next(config) 請(qǐng)求繼續(xù),如果請(qǐng)求成功,則會(huì)進(jìn)入 onResponse 鉤子,如果請(qǐng)求發(fā)生錯(cuò)誤,則會(huì)進(jìn)入 onError 。到請(qǐng)求回到 onResponse 里面的時(shí)候,可以使用油猴自帶的 GM_xmlhttpRequest 函數(shù)將相應(yīng)發(fā)送出去,這樣就可以獲取數(shù)據(jù)了,當(dāng)然還需要瀏覽器能觸發(fā)請(qǐng)求等行為,這部分也可以個(gè)油猴來完成,例如下面的代碼就是通過油猴觸發(fā)網(wǎng)站的點(diǎn)擊等事件:

// ==UserScript==
// @name         藥監(jiān)局列表頁數(shù)據(jù)采集
// @namespace    http://tampermonkey.net/
// @version      0.3.7.4
// @description  try to take over the world!
// @author       挖掘機(jī)小王子
// @match        http://app1.sfda.gov.cn/datasearchcnda/face3/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    // Your code here...
    // 觸發(fā)請(qǐng)求
    function triggerRequest() {

        // 點(diǎn)擊
        var interval = null
        var response = null
        interval = setInterval(function () {
            parseResponse() // 獲取響應(yīng)并且發(fā)出到Redis
            // 檢測是否需要翻頁
            if (startPage <= endPage){
                devPage(startPage++) // 翻頁
            }
            else {
                clearInterval(interval) // 結(jié)束
            }
        }, 500);

    }
    // 響應(yīng)解析
    function parseResponse(){
        var res = null
        res = document.querySelectorAll('tbody tr p a').forEach((item)=>{httpPost('http://127.0.0.1:8883/ajaxHook', item.href)});
    }
    // 發(fā)出響應(yīng)
    function httpPost(url, data) {
        fetch(url, {
            method: 'POST',
            mode: "cors",
            body: data
        });
    };
    var scope = '';
    scope = prompt('請(qǐng)輸入采集的頁數(shù)范圍,示例格式:100-200')
    var startPage = parseInt(scope.split('-')[0]) // 開始頁數(shù)
    var endPage = parseInt(scope.split('-')[1]) // 結(jié)束頁數(shù)
    // 執(zhí)行觸發(fā)
    triggerRequest()
})();

圖片.png

油猴實(shí)戰(zhàn)WebSocket通信

瀏覽器除了可以向外部發(fā)送數(shù)據(jù),其實(shí)也可以從外部獲取數(shù)據(jù)。由于HTTP協(xié)議的特殊性質(zhì),不能建立長連接,如果需要從外部獲取數(shù)據(jù)就需要不斷的請(qǐng)求外部的接口返回?cái)?shù)據(jù)。這種方式比較消耗資源,需要不斷的輪詢。想要瀏覽器和外部進(jìn)行雙向通訊的話可以使用WebSocket協(xié)議,該協(xié)議支持與瀏覽器進(jìn)行雙向通訊,瀏覽器可以獲取外部數(shù)據(jù),也可以給外部發(fā)送數(shù)據(jù),而且實(shí)時(shí)性更高,更加穩(wěn)定。國家藥監(jiān)局采用的是瑞數(shù)加密,6SQk6G2z 參數(shù)是在發(fā)送POST請(qǐng)求的時(shí)候,通過內(nèi)部的Hook機(jī)制,添加進(jìn)去的。也就是每個(gè)POST/GET請(qǐng)求都會(huì)添加該參數(shù),并且該參數(shù)是只能使用一次,如果一旦發(fā)送給服務(wù)器就不能再次使用。既然加密制造商可以Hook瀏覽器的POST請(qǐng)求,那么我們也一樣可以通過油猴Hook該請(qǐng)求,并且不讓請(qǐng)求發(fā)送出去(不會(huì)讓請(qǐng)求失效),并且把請(qǐng)求的參數(shù) 6SQk6G2z 通過WebSocket協(xié)議發(fā)送給我們自己的服務(wù)器,或者是發(fā)給我們的數(shù)據(jù)庫進(jìn)行存儲(chǔ),大批量的存儲(chǔ)該數(shù)值,然后采用Requests/Gevent等模塊實(shí)現(xiàn)發(fā)送請(qǐng)求。

油猴代碼:

// ==UserScript==
// @name         藥監(jiān)局Hook6SQk6G2z
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       挖掘機(jī)小王子 微信:EnjoyByte
// @match        http://app1.nmpa.gov.cn/data_nmpa/face3/*
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    // WebSockets
    var ws = new WebSocket("ws://127.0.0.1:8765");
    // 客戶端連接服務(wù)成功時(shí)觸發(fā)
    ws.onopen = function() {
        console.log('客戶端已連接!');
        ws.send("客戶端已連接!")
    }
    // 服務(wù)端發(fā)送消息過來觸發(fā)
    ws.onmessage = function(evt){
        console.log('服務(wù)端信息:', evt.data)
    }
    // 客戶端關(guān)閉觸發(fā)
    ws.onclose = function(){
        console.log('客戶端關(guān)閉!')
        clearInterval(intervalid)
    }
    // 客戶端出錯(cuò)觸發(fā)
    ws.onerror = function(evt){
        console.log("觸發(fā)失敗:", evt)
    }
    // Hook Url
    var open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function open(method, url) {
        // Hook URL
        console.log(url)
        ws.send(JSON.stringify({"url": url}))
    };
    // 不斷觸發(fā)下一頁事件的請(qǐng)求
    var intervalid = setInterval('devPage(2);', 500)
})();

在上面的代碼中,我Hook了 window.XMLHttpRequest.prototype.open 函數(shù),并且在新的函數(shù)里面不實(shí)現(xiàn)和請(qǐng)求相關(guān)的代碼,那么open函數(shù)就會(huì)失去發(fā)送請(qǐng)求的效果,而且該代碼是在 @run-at document-start 文檔開始的時(shí)候就盡快注入了。瑞數(shù)的Hook機(jī)制再在我的代碼基礎(chǔ)上進(jìn)行了Hook,當(dāng)隨便點(diǎn)擊頁面的下一頁的時(shí)候就會(huì)看到打印出了發(fā)送請(qǐng)求的網(wǎng)址,而 6SQk6G2z 參數(shù)就在請(qǐng)求的網(wǎng)址中。把該參數(shù)發(fā)送到程序外部用數(shù)據(jù)庫保存起來即可!外部的WebSocket代碼如下:

import asyncio
import websockets
from redis import StrictRedis


class WsServer:

    def __init__(self, redis_host='127.0.0.1', redis_port=6379):
        self.redis_cli = StrictRedis(
            host=redis_host,
            port=redis_port,
            decode_responses=True
        )

    #  WebSocket 服務(wù)
    async def server(self, websocket, path):
        while True:
            url_cookie_form_data = await websocket.recv()  # 不斷獲取瀏覽器數(shù)據(jù)
            print(url_cookie_form_data)
            if 'http:' in url_cookie_form_data:
                self.redis_cli.lpush("nmpa:urls", url_cookie_form_data)

if __name__ == '__main__':
    wsserver = WsServer()
    start_server = websockets.serve(wsserver.server, "127.0.0.1", 8765)
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()

上面的腳本是對(duì)瀏覽器發(fā)送來的數(shù)據(jù)的轉(zhuǎn)發(fā),將該數(shù)據(jù)轉(zhuǎn)發(fā)到Redis數(shù)據(jù)庫,下圖展示了轉(zhuǎn)發(fā)的數(shù)據(jù):

圖片.png

其實(shí)藥監(jiān)局除了需要 6SQk6G2z 還需要Cookie參數(shù),不過目前可以固定該參數(shù)也是可以的,另外對(duì)于詳情頁的數(shù)據(jù)還是需要瀏覽器進(jìn)行加密的,所以還是可以將需要加密的數(shù)據(jù)返回給瀏覽器讓他幫我們加密,然后返回給我們,我們?cè)谟贸绦虬l(fā)送請(qǐng)求,這樣速度可以快不少,我的測試是 Requests單線程 每小時(shí)10000條數(shù)據(jù)(大概是這樣)。后來采用協(xié)程編寫代碼效率極大提升。當(dāng)然如果擔(dān)心 6SQk6G2z 數(shù)據(jù)消耗的過快,產(chǎn)生的比較少,那么可以多開幾個(gè)標(biāo)簽頁就好了,這種就類似多線程了。如果覺得自己電腦必須一直開著,那么可以把腳本分發(fā)給任何有電腦的人,只需要打開瀏覽器就可以利用他們電腦的閑置資源,相當(dāng)于分布式的獲取6SQk6G2z值。

以上就是油猴腳本開發(fā)詳解+油猴爬蟲腳本實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于油猴腳本開發(fā)詳解+油猴爬蟲腳本實(shí)例的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文帶你了解ChatGPT?API的使用

    一文帶你了解ChatGPT?API的使用

    ChatGPT是OpenAI公司開發(fā)的一款基于自然語言處理技術(shù)的對(duì)話生成模型,,能夠自動(dòng)學(xué)習(xí)自然語言數(shù)據(jù)的特征,并生成高質(zhì)量的語言文本。本文將為大家來介紹一下ChatGPT的API使用,希望對(duì)大家有所幫助
    2023-02-02
  • 合成大西瓜開發(fā)源碼手把手教你運(yùn)行和部署大西瓜游戲項(xiàng)目(附源碼)

    合成大西瓜開發(fā)源碼手把手教你運(yùn)行和部署大西瓜游戲項(xiàng)目(附源碼)

    這篇文章主要介紹了合成大西瓜開發(fā)源碼手把手教你運(yùn)行和部署大西瓜游戲項(xiàng)目(附源碼),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • 最新IntelliJ IDEA 2020.2永久激活碼(親測有效)

    最新IntelliJ IDEA 2020.2永久激活碼(親測有效)

    今天一大波朋友反饋idea2020激活碼失效的問題,小編快馬加鞭給大家找到解決方案,本文以IDEA 2020.2.4激活碼破解教程為例給大家詳細(xì)介紹,需要idea2020激活碼的朋友快來參考下本文吧
    2020-11-11
  • 2022編程語言需求排名出爐:第一不是Python,也不是Java

    2022編程語言需求排名出爐:第一不是Python,也不是Java

    編程語言的流行程度、發(fā)展前景、就業(yè)市場這些一直都是程序員們非常關(guān)注的話題,需求排名是程序員們關(guān)注學(xué)習(xí)的風(fēng)向標(biāo),畢竟是市場經(jīng)濟(jì),學(xué)以致用,如果熱門編程不了解,都不好意思告訴別人你是程序員。編程語言的種類有超過200+,但還有很多不為人知。
    2022-12-12
  • bs架構(gòu)和cs架構(gòu)的區(qū)別_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    bs架構(gòu)和cs架構(gòu)的區(qū)別_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了bs架構(gòu)和cs架構(gòu)的區(qū)別,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • K8ssandra入門教程之Linux上部署K8ssandra到Kubernetes的過程

    K8ssandra入門教程之Linux上部署K8ssandra到Kubernetes的過程

    K8ssandra不僅幫助我們可以快速可靠地在Kubernetes上部署Cassandra,同時(shí)提供了許多組件,如監(jiān)控、備份、同步、訪問等,這篇文章給大家介紹K8ssandra入門教程之Linux上部署K8ssandra到Kubernetes的過程,一起看看吧
    2021-10-10
  • 前端使用svg圖片改色實(shí)現(xiàn)示例

    前端使用svg圖片改色實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了前端使用svg實(shí)現(xiàn)圖片改色的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 鴻蒙開發(fā)搭建flutter適配的開發(fā)環(huán)境

    鴻蒙開發(fā)搭建flutter適配的開發(fā)環(huán)境

    文章詳細(xì)介紹了在Windows系統(tǒng)上如何創(chuàng)建和運(yùn)行鴻蒙Flutter項(xiàng)目,包括使用flutter?doctor檢測環(huán)境、創(chuàng)建項(xiàng)目、編譯HAP包以及在真機(jī)上運(yùn)行項(xiàng)目,打包鴻蒙Flutter應(yīng)用的測試包和正式包的方法,并介紹了常見問題的解決方法
    2024-12-12
  • IntelliJ IDEA 2020最新注冊(cè)碼(親測有效,可激活至 2089 年)

    IntelliJ IDEA 2020最新注冊(cè)碼(親測有效,可激活至 2089 年

    這篇文章主要介紹了IntelliJ IDEA 2020最新注冊(cè)碼,親測有效,可激活至 2089 年,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • OAuth 2.0 概念及授權(quán)流程梳理

    OAuth 2.0 概念及授權(quán)流程梳理

    這篇文章主要介紹了OAuth 2.0 概念及授權(quán)流程梳理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評(píng)論