爬蟲之selenium

来源:https://www.cnblogs.com/Golanguage/archive/2020/03/23/12549798.html
-Advertisement-
Play Games

selenium基本操作 概念:基於瀏覽器自動化的模塊 :基於手機自動化的模塊的應用 環境的安裝 跟爬蟲之間的關聯? 可以實現模擬登陸 便捷的捕獲動態載入數據(可見即可得) 基本操作 導包: (web瀏覽器,driver驅動) 必須提供對應瀏覽器的驅動程式(谷歌,火狐...) "谷歌瀏覽器驅動下載地 ...


selenium基本操作

  • 概念:基於瀏覽器自動化的模塊

    • appnium:基於手機自動化的模塊的應用
  • 環境的安裝

    • pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
  • 跟爬蟲之間的關聯?

    • 可以實現模擬登陸
    • 便捷的捕獲動態載入數據(可見即可得)
  • 基本操作

    • 導包:from selenium import webdriver(web瀏覽器,driver驅動)

    • 必須提供對應瀏覽器的驅動程式(谷歌,火狐...)

    • 實例化一個瀏覽器對象

      bro = webdriver.Chrome(executable_path='./chromedriver.exe')
      # Chrome 谷歌瀏覽器 executable_path 瀏覽器驅動路徑
      
    • 標簽定位

      • find系列的函數
    • 標簽對象.send_keys():向指定標簽中錄入數據

    • 提交標簽.click()

    • js註入:瀏覽器對象.execute_script("js代碼")

    • 瀏覽器對象.page_source :返回當前頁面的頁面源碼數據,包含動態載入數據

    • 關閉瀏覽器:瀏覽器對象.quit()

  • 缺點

    • 爬取的效率比較低下
  • 什麼時候用selenium

    • 動態載入的數據requests模塊實在爬取不到,使用selenium

示例代碼

  • 登陸京東,搜索商品
from selenium import webdriver
from time import sleep

# 實例化瀏覽器對象
bro = webdriver.Chrome(executable_path='./chromedriver.exe')   # Chrome 谷歌瀏覽器 executable_path 瀏覽器驅動地址 
# 制定一些自動化的操作

# 發起請求
bro.get('https://www.jd.com')
# 如何進行標簽定位
search_tag = bro.find_element_by_id('key')
# 向文本框中錄入數據
search_tag.send_keys('mac pro')
sleep(2)
btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
btn.click()
sleep(2)
# 註入JS代碼
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
# page_source :返回當前頁面的頁面源碼數據,包含動態載入數據
print(bro.page_source)

# 關閉瀏覽器
bro.quit()

案例:使用selenium捕獲要藥監總局的動態載入數據

  • 該網站的數據是動態載入的,來測試selenium如何便捷的捕獲動態載入數據
  • 網址:http://125.35.6.84:81/xk/
from selenium import webdriver
from time import sleep
from lxml import etree

# 實例化瀏覽器對象
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
# 發起請求
bro.get('http://125.35.6.84:81/xk/')
sleep(1)
# 第一頁的頁面源碼數據
page_text = bro.page_source
all_page_text = [page_text]
for i in range(1,5):
    # 找到下一頁對應的標簽
    a_tag = bro.find_element_by_xpath('//*[@id="pageIto_next"]')
    # 對下一頁的標簽發起點擊
    a_tag.click()
    sleep(1)
    # page_source 獲取當前頁面的源碼數據(涵動態載入)
    page_text = bro.page_source
    all_page_text.append(page_text)
for page_text in all_page_text:
    tree = etree.HTML(page_text)
    # xpath解析到name對應的標簽
    li_lst = tree.xpath('//*[@id="gzlist"]/li')
    for li in li_lst:
        name = li.xpath('./dl/@title')[0]
        print(name)
sleep(2)
bro.quit()

動作鏈

動作鏈:一系列連續的動作

  • 導包:from selenium.webdriver import ActionChains
  • NoSuchElementException報錯:沒有定位到指定的標簽
    • 定位的標簽是存在於一張嵌套的子頁面中,如果想定位之頁面中的指定標簽的話需要:
      • 瀏覽器對象.switch_to.frame('iframe標簽id的屬性值'):將當前瀏覽器頁面切換到指定的子頁面範圍中
  • 針對指定的瀏覽器實例化一個動作鏈對象
    • action = ActionChains(bro)
  • 點擊且長按指定的標簽
    • action.click_and_hold(tagName)
  • 偏移
    • action.move_by_offset(xoffset, yoffset) 一點一點偏移
    • action.move_to_element(to_element)
    • action.move_to_element_with_offset(to_element, xoffset, yoffset)
  • 偏移.perform():動作鏈立即執行

示例代碼

from selenium import webdriver
from selenium.webdriver import ActionChains
from time import sleep

bro = webdriver.Chrome("./chromedriver.exe")
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

# 標簽定位
bro.switch_to.frame('iframeResult')
div_tag = bro.find_element_by_id('draggable')

# 需要使用ActionChains定製好的行為動作

# 針對當前瀏覽器頁面實例化了一個動作鏈對象
action = ActionChains(bro)
# 點擊且長按一個指定的標簽
action.click_and_hold(div_tag)

for i in range(1,7):
    # 一點一點遷移
    action.move_by_offset(10,15).perform()  # perform() 是動作鏈立即執行
    action.move_to_element
    action.move_to_element_with_offset
    sleep(0.5)

無頭瀏覽器

  • 概念:沒有可視化界面的瀏覽器
  • phantomJS無頭瀏覽器,幾乎不用了,停止更新維護了,現在不用了

谷歌無頭瀏覽器

  • 就是本機安裝的谷歌瀏覽器,只是需要通過代碼進行相關配置就可以變成無頭瀏覽器
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# 無頭瀏覽器開整
# 實例化options對象
chrome_options = Options()
# 調用add_argument方法,進行自定義配置
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

bro = webdriver.Chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options)
bro.get('https://www.baidu.com')
# 截屏
bro.save_screenshot('./1.png')
print(bro.page_source)

規避檢測

  • webServer是如何檢測到我們的請求是否使用了selenium

    • 網站開發者工具Consloe中註入js代碼:window.navigator.webdriver
      • true:請求是基於selenium發起的(異常請求)
      • undefined:請求是基於瀏覽器發起的(正常請求)
  • 環境配置

    • 本機谷歌瀏覽器的驅動程式所在的目錄路徑添加到環境變數中

    • 使用本機谷歌的驅動程式開啟一個瀏覽器

      • chrome.exe --remote-debugging-port=9222 --user-data-dir="D:\selenum\AutomationProfile"

        9222:埠(任意空閑埠)

        "D:\selenum\AutomationProfile":已經事先存在的一個空目錄

使用托管機制

  • Consloe中註入js代碼:window.navigator.webdriver,雖然會返回true,但不會提示請停用以開發者模式運行的擴展程式,相當於自己打開的瀏覽器
# 終端先運行如下代碼
chrome.exe --remote-debugging-port=9222 --user-data-dir="D:\selenum\AutomationProfile"

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_experimental_option('debuggerAddress','127.0.0.1:9222')

# 代碼托管打開的瀏覽器,不會實例化一個新的瀏覽器
driver = webdriver.Chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options)
driver.get('http://www.taobao.com')
  • 老版本的selenium規避檢測的操作
    • 這個目前會被檢測到
from selenium import webdriver
from selenium.webdriver import ChromeOptions
 
option = ChromeOptions()     #實例化一個ChromeOptions對象
option.add_experimental_option('excludeSwitches', ['enable-automation'])  #以鍵值對的形式加入參數
 
bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)  #在調用瀏覽器驅動時傳入option參數就能實現undefined

模擬登陸

12306模擬登陸

  • URL:12306登陸

  • 分析:

    • 識別的驗證碼圖片必須通過截圖獲取驗證碼然後存儲到本地
      • 登陸操作和唯一的驗證碼圖片一一對應
  • 基於超級鷹識別驗證碼登錄,類型9004

# 超級鷹的包
import requests
from hashlib import md5

class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password =  password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 圖片位元組
        codetype: 題目類型 參考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:報錯題目的圖片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()

# 封裝一個驗證碼識別的函數
def transform_code(imgPath,imgType):
    chaojiying = Chaojiying_Client('超級鷹用戶名', '超級鷹用戶名對應的密碼', '軟體ID')
    im = open(imgPath, 'rb').read()
    return chaojiying.PostPic(im, imgType)['pic_str']


# 模擬登陸實現代碼

from time import sleep
from PIL import Image	# pip install Pillow
from selenium import webdriver
from selenium.webdriver import ActionChains

# 實例化一個谷歌瀏覽器對象
bro = webdriver.Chrome(executable_path="./chromedriver.exe")
# 發起請求
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
# 登錄頁面第一個展示的是掃碼,點擊帳號密碼登錄
bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
sleep(2) # 等待2秒,載入驗證碼圖片
# 定位到用戶名密碼框,輸入帳號密碼
bro.find_element_by_id('J-userName').send_keys('xxxxxxxx')  # 12306用戶名
bro.find_element_by_id('J-password').send_keys('********')  # 12306用戶名對應的密碼

# 驗證碼的點擊操作
bro.save_screenshot('./12306.png')# 將頁面當作圖片保存到本地
# 將驗證碼圖片的標簽定位到
img_tag = bro.find_element_by_id('J-loginImg')
# 驗證碼的坐標和大小
location = img_tag.location
size = img_tag.size

# 裁剪的範圍,這個根據截圖自己情況調整,自己調試的(699, 284, 1015, 472)
rangle = (int(location['x'])-65,int(location['y']),int(location['x']+size['width'])-49,int(location['y']+size['height']))

# 使用Image類根據rangle裁剪範圍進行驗證碼圖片的裁剪
i = Image.open('./12306.png')  # bytes類型數據
frame = i.crop(rangle)  # 驗證碼對應的二進位數據
frame.save('./code.png')
img_coor = transform_code('./code.png',9004)  # 返回坐標值 274,146|37,147

# 將坐標字元串轉換為嵌套的列表
all_lst = []	# [[274,146],[37,147]...]
if '|' in img_coor:
    lst_1 = img_coor.split("|")
    count_1 = len(lst_1)
    for i in range(count_1):
        xy_lst = []
        x = int(lst_1[i].split(',')[0])
        y = int(lst_1[i].split(',')[1])
        xy_lst.append(x)
        xy_lst.append(y)
        all_lst.append(xy_lst)
else:
    x = int(img_coor.split(',')[0])
    y = int(img_coor.split(',')[1])
    xy_lst = []
    xy_lst.append(x)
    xy_lst.append(y)
    all_lst.append(xy_lst)

for data in all_lst:
    # 每個data都是一個列表中有2個元素
    x = data[0]
    y = data[1]
    # 實例化一個動作鏈,在指定範圍(驗證碼標簽範圍),找到x,y坐標,點擊,動作鏈立即執行
    ActionChains(bro).move_to_element_with_offset(img_tag,x,y).click().perform()
    # 執行一次等待0.5秒,防止過快
    sleep(0.5)

# 點擊登錄按鈕,實現登錄
bro.find_element_by_id('J-login').click()
sleep(2)
# 關閉瀏覽器
bro.quit()

Pyppeteer


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 開篇 在一門編程語言中,往往會提供大量的運算符。按功能來分的話,有算術運算符、賦值運算符、關係運算符、邏輯運算符、位運算符等。這些對於大家來說都不陌生。但是,本期的主角『位運算』符相對而言是比較少去使用的。因為位運算符主要針對兩個二進位數進行位運算。 巧用位運算能極大的精簡代碼和提高程式效率。所以, ...
  • 圖解Java設計模式之裝飾者模式 星巴克咖啡訂單項目(咖啡館) 方案 1 - 解決星巴克咖啡訂單項目 方案1 - 解決星巴克咖啡訂單問題分析 方案 2 - 解決星巴克咖啡訂單(好點) 方案2 - 解決星巴克咖啡訂單問題分析 裝飾者模式定義 裝飾者模式原理 裝飾者模式解決星巴克咖啡訂單 裝飾者模式下的 ...
  • 此項目為Springboot工作流版本 windows 風格,瀏覽器訪問操作使用,非桌面應用程式。 1.代碼生成器: [正反雙向](單表、主表、明細表、樹形表,快速開發利器) freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表sql腳本、處理類、service等完整模塊 ...
  • CSDN看到一篇介紹架構設計的博客,內容提綱挈領,內容豐富。依據原文整理,加上自己的理解和總結。 推薦給大家。點擊原文可以查看出處。 原文鏈接:https://blog.csdn.net/hguisu/article/details/78258430 什麼是架構和架構本質 在軟體行業,對於什麼是架構 ...
  • 定義: 工廠方法模式:定義一個用於創建對象的介面,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。 代碼實例: 這裡還是接著上篇簡單工廠模式的那個例子,改成工廠方法模式。 1、創建一個抽象類 ApptEncoder /** * 抽象類 * Class ApptEncoder */ a ...
  • 定義: 簡單工廠模式:將調用者和創建者分離,實現解耦,調用者直接向工廠請求,通過工廠去選擇需要實例化的對象,用一個單獨的類來做這個創建實例的過程。 代碼實例: 問題:假設一個關於個人事務管理的項目中有許多類型的對象,其中一個是 Appointment 對象,現在需要通過一種稱為 BloggsCal ...
  • Spring Boot 是微服務中最好的 Java 框架. 我們建議你能夠成為一名 Spring Boot 的專家。本文精選了三十五個常見的Spring Boot知識點,祝你一臂之力! 問題一 Spring Boot、Spring MVC 和 Spring 有什麼區別? 1、Spring Sprin ...
  • 一、Harbor安裝環境要求 硬體環境: 1)CPU 2核以上,最好4核以上 2)記憶體4G以上,最好8G以上 3)硬碟空間至少40G,最好160G以上 軟體環境: 1)docker v17.06以上版本 2)docker compose v1.18.0以上版本 3)Openssl 更新到最新版(一般 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...