PHP 初心者が WordPress の プラグイン 作成 ! part43 ( ヘッドレスブラウザでココナラのブログを投稿成功!)

この記事では PHP 初心者 が WordPress プラグイン を 作成 します。 part43 ではヘッドレスブラウザでココナラへの投稿を行います。

前回はついにココナラブログの公開設定への入力を行うことができました。
さらに投稿まで成功しました。

PHP 初心者が WordPress の プラグイン 作成 ! part42 ( ココナラの公開設定を調査 その12 ついに投稿成功!)

今回はヘッドレスブラウザから投稿を再現させてみようと思います。

PHPに組み込む

試行錯誤し、投稿まで成功したJavaScriptをPHPに組み込みます。

「投稿する」ボタンを押す直前まで処理をしてみます。

$evaluation = $page->evaluate(
    '(() => {

        // 公開設定をクリック
        document.querySelector("button.button.c-blogPost_triggerPublish").click();

        // カテゴリの選択
        document.querySelector("div.c-blogPublishing_category select option[value=\"9\"").selected = true;
        document.querySelector("div.c-blogPublishing_category select").dispatchEvent(new Event("change"));
        // ハッシュタグの指定
        obj = document.querySelector("[data-v-46ae5ace]");
        obj.__vue__.blogTagNames.push(" IT");
        obj.__vue__.blogTagNames.push(" WordPress");

    })()');

汗と涙の結晶(死語)、用意できました!

さてどうですかね・・・

http://localhost:8099/index.php にアクセス・・・
む!?公開設定のモーダルが表示されていませんでした。

 

スリープその1

ブラウザでの通常操作においても「公開設定」のボタンを押した後少し「間」があります。
これをJavaScriptで再現してみました。

$evaluation = $page->evaluate(
    '(() => {
        // ミリ秒間待機する
        function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        // 公開設定をクリック
        document.querySelector("button.button.c-blogPost_triggerPublish").click();
        
        // 5秒待機
        await sleep(5*1000);

        // カテゴリの選択
        document.querySelector("div.c-blogPublishing_category select option[value=\"9\"").selected = true;
        document.querySelector("div.c-blogPublishing_category select").dispatchEvent(new Event("change"));
        // ハッシュタグの指定
        obj = document.querySelector("[data-v-46ae5ace]");
        obj.__vue__.blogTagNames.push(" IT");
        obj.__vue__.blogTagNames.push(" WordPress");

    })()');

http://localhost:8099/index.php にアクセス!

・・・同じ結果でした。(画像省略)

スリープその2

ヘッドレスブラウザの画面遷移同様に「公開設定」ボタンを押す部分のみ分離してPHPでのスリープを実装してみました。

// 公開設定ボタンをクリック
try{
    $evaluation = $page->evaluate('document.querySelector("button.button.c-blogPost_triggerPublish").click();')->waitForPageReload(Page::LOAD, 10000);
} catch(OperationTimedOut $e) {
    echo "長すぎでもこれは仕方ない。その2";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
// 公開設定画面の項目を入力
$evaluation = $page->evaluate(
    '(() => {
        // カテゴリの選択
        document.querySelector("div.c-blogPublishing_category select option[value=\"9\"").selected = true;
        document.querySelector("div.c-blogPublishing_category select").dispatchEvent(new Event("change"));
  
        // ハッシュタグの指定
        obj = document.querySelector("[data-v-46ae5ace]");
        obj.__vue__.blogTagNames.push(" IT");
        obj.__vue__.blogTagNames.push(" WordPress");

    })()');

さて・・・
お?無事に入力できたようですね😄

 

ココナラブログ投稿

いよいよ投稿です。
「公開する」ボタンを押す処理を含め、ここまでのコーディングをすべて公開します。
※デバッグコードも含まれています。

<?php

// autoloadを読み込む
require 'vendor/autoload.php';

use HeadlessChromium\BrowserFactory;
use HeadlessChromium\Page;

use HeadlessChromium\Exception\OperationTimedOut;
use HeadlessChromium\Exception\NavigationExpired;

// whereis chromiumでパスを探した
$browserFactory = new BrowserFactory('/usr/bin/chromium');

// for Docker option
$options = [
    'headless' => true,
    'noSandbox' => true ,
    'sendSyncDefaultTimeout' => 100000,
    'windowSize'      => [1920, 1000],
    'userAgent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
    'enableImages'    => false,
];

// starts headless chrome
$browser = $browserFactory->createBrowser($options);

// creates a new page and navigate to an url
$page = $browser->createPage();
// $page->navigate('https://www.google.co.jp')->waitForNavigation();
$page->navigate('https://coconala.com/')->waitForNavigation();

// get page title
//$pageTitle = $page->evaluate('document.title')->getReturnValue();
// ココナラにログインする(30秒待つ)
$evaluation = $page->evaluate('document.querySelector("li.c-mainNavBeforeLogin_item-pc a:first-child").click()')->waitForPageReload(Page::LOAD, 30000);

// アカウント入力(実際は自身のアカウントを入力)
$evaluation = $page->evaluate(
    '(() => {
        document.querySelector("#UserLoginEmail").value = "hoge";
        document.querySelector("#UserLoginPassword").value = "fuga";
        document.querySelector("form#UserLoginForm button[type=\"submit\"]").removeAttribute("disabled");
    })()');

// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar01.png', 10000);
try{
    $evaluation = $page->evaluate('document.querySelector("form#UserLoginForm button[type=\"submit\"]").click()')->waitForPageReload(Page::LOAD, 30000);
} catch(OperationTimedOut $e) {
    echo "長すぎ";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar02.png', 10000);

// ブログのページに遷移
try{
    $evaluation = $page->evaluate('document.querySelector("a.c-subLink_item-blog").click()')->waitForPageReload(Page::LOAD, 30000);
} catch(OperationTimedOut $e) {
    echo "長すぎ";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar03.png', 10000);

// ブログの種類選択
try{
    $evaluation = $page->evaluate('document.querySelector("button.button.is-primary").click()')->waitForPageReload(Page::LOAD, 10000);
} catch(OperationTimedOut $e) {
    echo "長すぎでもこれは仕方ない。";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar04.png', 10000);

// ブログを記述する
$evaluation = $page->evaluate(
    '(() => {
        obj = document.querySelector("[data-v-46ae5ace]");
        obj.__vue__.title = "ヘッドレスブラウザから書き込み!"
        obj.__vue__.body = "<div data-v-22617325=\"\" class=\"c-blogBody_text\">ついに書き込むことに成功</div><div data-v-22617325=\"\" class=\"c-blogBody_text\">しました!</div>";
        obj.__vue__.bodyText = "ついに書き込むことに成功/nしました!";
        obj.__vue__.blogEmpty = false;
    })()');
// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar05.png', 10000);

// 公開設定ボタンをクリック
try{
    $evaluation = $page->evaluate('document.querySelector("button.button.c-blogPost_triggerPublish").click();')->waitForPageReload(Page::LOAD, 10000);
} catch(OperationTimedOut $e) {
    echo "長すぎでもこれは仕方ない。その2";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
// 公開設定画面の項目を入力
$evaluation = $page->evaluate(
    '(() => {
        // カテゴリの選択
        document.querySelector("div.c-blogPublishing_category select option[value=\"9\"").selected = true;
        document.querySelector("div.c-blogPublishing_category select").dispatchEvent(new Event("change"));
  
        // ハッシュタグの指定
        obj = document.querySelector("[data-v-46ae5ace]");
        obj.__vue__.blogTagNames.push(" IT");
        obj.__vue__.blogTagNames.push(" WordPress");

    })()');

// screenshot(10秒待機)
//$page->screenshot()->saveToFile('/var/www/html/bar06.png', 10000);

// 投稿するをクリック
try{
    $evaluation = $page->evaluate('document.querySelector("button[data-v-6c22d71e].button.is-primary").click();')->waitForPageReload(Page::LOAD, 10000);
} catch(OperationTimedOut $e) {
    echo "長すぎでもこれは仕方ない。その3";
} catch(NavigationExpired $e) {
    echo "別のページが読み込まれた";
}
$page->screenshot()->saveToFile('/var/www/html/bar07.png', 10000);

// bye
$browser->close();

?>

ものすごく惰性で実装した感じが出てますね😅

確認

いよいよです!

http://localhost:8099/index.php アクセスしてみます。
・・・おおおおお!ついにできましたよ😍

 

通常のブラウザでも確認しておきましょう。

グレイト!
ようやくヘッドレスブラウザでのブログ投稿ができるようになりました。

まとめ

ヘッドレスブラウザを用いてココナラのブログに投稿を行いました。
ようやく投稿に成功しました。

しかしまだ課題はあります。

  • コードをもう少しきれいにしたい
  • 時間かかりすぎ
  • PHPへの本格的な組み込み
  • Vue.js + Nuxt.js結局よくわからない😑
  • まだプラグインとして組み込めていない!←ここが重要

これらを進めていきたいと思います。

今日はここまで!