Pyppeteerライブラリ4:Pyppeteerページ操作(下)

カスタムJSスクリプトを実行する

Pyppeteer Pageオブジェクトは一連の評価メソッドを提供します。これらのメソッドを使用して、いくつかのカスタムJSコードを実行でき、主に次の3つのAPIを提供します。

(1)page.evaluate(pageFunction [、... args])、pageFunctionの実行結果を返します。pageFunctionはページで実行される関数または式を表し、argsはpageFunctionに渡されるパラメーターを表します

例:

await page.goto('https://www.baidu.com')
# 输出字符串
await page.evaluate('alert("在浏览器执行js脚本!")')
# 将元素作为参数传入 page.evaluate
element = await page.J('#ul>a[name="tj_trtieba"]')
print(await page.evaluate('el => el.innerHTML', element))
print(await page.evaluate('el => el.href', element)
# 执行函数
el = await page.evaluate('() => document.querySelector("#su").value')
print(el)

(2)page.evaluateHandle(pageFunction [、... args])、このメソッドとpage.evaluateの唯一の違いは、このメソッドがページタイプ(JSHandle)を返すことです

例:

await page.goto('https://www.baidu.com')
el = await page.evaluateHandle('() => document.querySelector("#su").value')
print(type(el))
print(el.toString())

(3)page.evaluateOnNewDocument(pageFunction [、... args])。指定された関数は、それが属するページが作成され、それが属するページのスクリプトが実行される前に呼び出されます。多くの場合、ページのJS環境を変更するために使用されます。

以下は、中間JSの挿入と、Taobaoがブラウザーを検出するために呼び出すJSを変更した結果です。

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch({
        'headless': False,
        'args': ['--no-sandbox', '--window-size=1366,768']
    })
    page = await browser.newPage()
    await page.setViewPort({'width': 1366, 'height': 768})
    await page.evaluateOnNewDocument('''() => {
        Object.defineProperty(navigator, 'webdriver', {get: () => false });
    }''')
    await page.goto('https://login.taobao.com')
    await page.evaluate('alert(navigator.webdriver)')
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

元素操作

ElementHandleは、ページ内のDOM要素を表します。page.querySelector()メソッドを使用して作成できます。DOM要素には、ページと同じメソッドがいくつかあります:J()、JJ()、Jeval()、JJeval()、screenshot()、type()、click()、tap()。さらに、いくつかの便利な方法があります。

(1)要素の境界ボックスの座標を取得します:boundingBox()、要素の境界ボックスを返します(メインフレームに対して)=> x座標、y座標、幅、高さ

(2)要素は表示されていますか:isIntersectingViewport()

(3)ファイルをアップロード:uploadFile(* filepaths)

(4)ElementHandleクラスはFrameクラスに変換されます:contentFrame()、ハンドルがiframeを参照しない場合、Noneを返します。

(5)要素にフォーカスします:focus()

(6)マウスに関連:hover()、要素の上にマウスを置きます

(7)キーボードに関連:press(key [、options])、key、keyはキーの名前を表し、オプションを設定できます:

  • text(string)-指定した場合、このテキストを使用して入力イベントを生成します
  • delay(number)-キーダウンとキーアップの間の待機時間、デフォルトは0

 

鼠标事件

Mouseクラスは、ビューポートの左上隅を基準にしたメインフレームのCSSピクセルで動作します。

(1)page.mouse.down([options])マウスを押すと、オプションを構成できます。

  • button(str)どのキーが押されたか、オプションの値は[左、右、中央]、デフォルトは左、つまり左マウスボタン
  • clickCount(int)プレス、クリック、ダブルクリックなどの回数

(2)page.mouse.up([options])マウスを離します。オプションは上記と同じです

(3)page.mouse.move(x、y、[options])マウスを指定された位置に移動し、options.stepsは移動のステップ長を表します

(4)page.mouse.click(x、y、[options])指定された位置でのマウスクリック、これは実際にはmouse.moveとmouse.downまたはmouse.upのショートカット操作です

 

模拟登录的验证码处理

可能用到的方法:

  • ElementHandle.boundingBox()、ElementHandle.hover()
  • mouse.down()、mouse.move()、mouse.up()、mouse.click()

例1:Taobao確認コードのスライダーをドラッグする

(1)淘宝網の検証コード検証モジュールがブラウザー環境を検出し、JSを挿入します。

(2)可能な限りユーザー操作をシミュレートします。乱数はPyppeteerの実行速度を遅くします。

例:

import asyncio
import random
from pyppeteer import launch

async def main():
    browser = await launch({
        'headless': False,
        'args': ['--no-sandbox', '--window-size=1366,768']
    })
    page = await browser.newPage()
    await page.setViewport({'width': 1366, 'height': 768})
    await page.evaluateOnNewDocument('''() => {
        Object.defineProperties(navigator, { webdriver:{ get: () => false}}
    }''')
    await page.evaluateOnNewDocument('''() => {
        window.navigator.chrome = { runtime: {}, };
    }''')
    await page.evaluateOnNewDocument('''() => {
        Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
    }''')
    await page.evaluateOnNewDocument('''() => {
        Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); 
    }''')
    await page.goto('https://login.taobao.com')
    await asyncio.sleep(2)
    try:
        await page.click('div.login-links > a.forget-pwd.J_Quick2Static')
    except:
        pass
    await asyncio.sleep(2)
    await page.type('#TPL_username_1', '123123123', {'delay': random.randint(60, 121)})
    await page.type('#TPL_password_1', '1234567890', {'delay': random.randint(100, 151)})
    await asyncio.sleep(1.5)
    try:
        el = await page.querySelector('#nc_1_n1z')
        box = await el.boundingBox()
        await page.hover('#nc_1_n1z')
        await page.mouse.down()
        await page.mouse.move(box['x'] + random.randint(333, 999), box['y'], {'steps': 5})
        await page.mouse.up()
    except:
        pass
    await asyncio.sleep(1.8)
    await page.click('#J_SubmitStatic')
    await asyncio.sleep(5)
    await browser.close()


asyncio.get_event_loop().run_until_complete(main())

例2:鉄道12306タッチ検証コード

(1)12306の検証コードを分析します。これは次のようになります。

マウスクリックの位置を各画像の中心点にすることができます。

この値は次のように計算できます。

  • 幅:37、37 * 3、37 * 5、37 * 7; 即37、111、185、259
  • 高さ(0):70
  • 高さ(1):70 +(190-30)/ 2、つまり150

検証コード画像の座標がx、yの場合、2番目と7番目の画像の位置は、(x + 111、y + 70)、(x + 185、y + 150)として表すことができます。

例:

import asyncio
import random
from pyppeteer import launch

async def main():
    browser = await launch({
        'headless': False,
        'args': [f'--window-size=1366,768', '--no-sandbox']
    })
    page = await browser.newPage()
    await page.goto('https://kyfw.12306.cn/otn/login/init',
                    {'waitUntil': 'networkidle0'})
    await page.setViewport({'width': 1366, 'height': 768})
    # 等待验证码加载
    code = await page.waitForFunction(
        '''() => document.querySelector("img.touclick-image")''')
    # 验证码截图
    await code.screenshot({'path': 'code.png'})
    # 获取验证码坐标
    box = await code.boundingBox()
    await page.waitFor(2 * 1000)
    # 点击第2张图片
    await page.mouse.click(box['x']+111, box['y']+70)
    await page.waitFor(random.randint(567, 3456))
    # 点击第7张图片
    await page.mouse.click(box['x']+185, box['y'] + 150)
    await page.waitFor(3 * 1000)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

(2)コーディングプラットフォーム:12306

確認コードの認識は少し人間味がありません;コーディングプラットフォームとのドッキングはより良い選択です;原則はバイトで確認コード画像を送信し、文字列を返すこと183,68|193,161です。

Super EagleコーディングプラットフォームAPI:

chaojiying.py

#!/usr/bin/env python
# coding:utf-8

import requests
from hashlib import md5

class CodeInfo(object):

    def __init__(self):
        self.username = '用户名'
        self.password = md5('密码'.encode('utf8')).hexdigest()
        self.soft_id = '96001' # 用户中心 >> 软件ID,生成一个替换96001
        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 process(self, im, codetype):
        url = 'http://upload.chaojiying.net/Upload/Processing.php'
        params = {'codetype': codetype}
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post(url, data=params, files=files, headers=self.headers)
        return r.json()

    def report(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        url = 'http://upload.chaojiying.net/Upload/ReportError.php'
        params = {'id': im_id}
        params.update(self.base_params)
        r = requests.post(url, data=params, headers=self.headers)
        return r.json()

if __name__ == '__main__':
    im = open('code.png', 'rb').read()
    """
    9004 验证码类型
    参考 http://www.chaojiying.com/price.html
    """
    answer = CodeInfo().process(im, 9004)
    print(answer)

ログイン例12306

import asyncio
import random
from pyppeteer import launch
from chaojiying import CodeInfo

def pic_info():
    im = open('code.png', 'rb').read()
    answer = CodeInfo().process(im, 9004)
    print(answer)
    return answer['pic_str']

async def main():
    browser = await launch({
        'headless': False,
        'args': ['--window-size=1366,768', '--no-sandbox']
    })
    page = await browser.newPage()
    await page.goto('https://kyfw.12306.cn/otn/login/init',
                    {'waitUntil': 'networkidle0'})
    await page.setViewport({'width': 1366, 'height': 768})
    code =await page.waitForFunction(
        '''() => document.querySelector("img.touclick-image")''')
    await code.screenshot({'path': 'code.png'})
    await page.waitFor(2 * 1000)
    await page.type('#username', '[email protected]',
                    {'delay': random.randint(60, 121)})
    await page.waitFor(random.randint(345, 1234))
    await page.type('#password', '1234567890',
                    {'delay': random.randint(100, 151)})
    pic_str = pic_info()
    points = list(set(pic_str.split('|')))
    box = await code.boundingBox()
    for point in points:
        p = point.split(',')
        await page.mouse.click(box['x']+int(p[0]), box['y']+int(p[1]))
        await page.waitFor(random.randint(567, 3456))
    await page.click('#loginSub')
    await page.waitFor(5 * 1000)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

键盘事件

キーボードは、仮想キーボードを管理するためのインターフェースを提供します。高度なインターフェースはkeyboard.typeで、元の文字を受け取り、ページ上で対応するkeydown、keypress / input、keyupイベントを生成します。

より細かい制御(仮想キーボード)を行うには、keyboard.down、keyboard.up、およびkeyboard.sendCharacterを使用して、イベントが実際のキーボードによって生成されたかのように、手動でイベントをトリガーできます。

キーボードのいくつかのAPIは次のとおりです。

  • keyboard.down(key [、options])はkeydownイベントをトリガーします
  • keyboard.press(key [、options])キーを押すと、キーは左側の「ArrowLeft」などのキーの名前を表します。
  • keyboard.sendCharacter(char)文字を入力してください
  • keyboard.type(text、options)文字列を入力してください
  • keyboard.up(key)はkeyupイベントをトリガーします

 

いくつかの文字列を選択して例を削除するには、Shiftキーを押し続けます。

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch({'headless': False})
    page = await browser.newPage()
    await page.goto('https://www.baidu.com', {'waitUntil': 'networkidle0'})
    el = await page.J('#kw')
    await el.focus()
    await page.keyboard.type('Hello, World!')
    await page.keyboard.press('ArrowLeft')
    await page.keyboard.down('Shift')
    for _ in ' World':
        await page.keyboard.press('ArrowLeft')
    await page.keyboard.press('ArrowLeft')
    await page.keyboard.up('Shift')
    await page.keyboard.press('Backspcae')
    # 结果字符串最终为'Hello!'
    await asyncio.sleep(5)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

押された  A例:

await page.keyboard.down('Shift')
await page.keyboard.press('KeyA')
await page.keyboard.up('Shift')

詳細なヘルス名のマッピングは、ソースコードで確認できます。

Lib \ site-packages \ pyppeteer \ us_keyboard_layout.py

内嵌框架

Page.frames、ElementHandle.contentFrameメソッドを介して取得でき、同時にページを持つ複数のメソッドがあります。

**その他:

  • childFramesは子フレームを取得し、リストを返します
  • parentFrameは親フレームを返します
  • content()はフレームのHTMLコンテンツを返します
  • url get url
  • 名前は名前を取得します
  • title()タイトルを取得します


 

例:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch({'headless': False})
    page = await browser.newPage()
    await page.goto('http://www.4399.com', {'waitUntil': 'networkidle0'})
    await page.click('#login_tologin')
    await asyncio.sleep(1)
    frame = page.frames[1]
    await frame.type('#username', '123456789')
    await frame.type('#j-password', '998765433')
    await asyncio.sleep(5)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

または:

await page.click('#login_tologin')
await asyncio.sleep(1)
element = await page.J('iframe')
frame = await element.contentFrame()

 

おすすめ

転載: blog.csdn.net/zhangge3663/article/details/108376903