masalibの日記

システム開発、運用と猫の写真ブログです

puppeteerでCMSの記事更新処理

puppeteerを使って記事更新するのをやってみました
ファイルアップもできました

概要

記事更新の概要は以下のとおりです
1・ログイン処理
2・リストページ遷移
3・新規追加ボタンを押す
4・新規作成の画面に遷移される
5・新規作成画面で記事内容を投稿する
  テキストボックス、テキストエリア、チェックボックス、ファイル添付
6・投稿内容の確認画面に遷移する
7・確認画面から完了画面に遷移する



プログラム

ログインの処理は前回の処理を参照
masalib.hatenablog.com

const puppeteer = require('puppeteer');
const fs = require('fs');
const cookies_path = './cookies_masalib_site.json';
const loginmodule = require('./loginWithCookie.js');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
  });
  const page = await browser.newPage();
  await page.setViewport({width: 1280, height: 700});

  await loginmodule.loginproc(page);
  await page.waitFor(1000);

  //一覧ページ
  await page.goto('http://masalib.jp/admin/blog/ArticleList.asp?page=1');

  console.log(page.url());
  const inputElement = await page.$('table > tbody > tr > td:nth-child(2) > div > input[type=button]');
  await inputElement.click();	//新規作成ボタンをクリック
  await page.waitFor(1000);
  console.log(page.url());	//新規作成のページに遷移しているの確認


  //投稿内容
  //テキストボックス
  await page.focus('input[name=art_title]');
  await page.type("art_title_test");
  await page.focus('input[name=keyword]');
  await page.type("keyword_test");

  //テキストエリア
  await page.focus('textarea[name=art_nom_text]');
  await page.type("art_nom_text_test");
  await page.focus('textarea[name=art_text]');
  await page.type("art_text_test");

  //チェックボックス
  var inputElement2 = await page.$('center > form > table > tbody > tr:nth-child(2) > td > table > tbody > tr:nth-child(2) > td.data > input[type="checkbox"]');
  await inputElement2.click();

  //ファイルアップ
  var filePath =  __dirname + '/icon.jpg';
  console.log("filePath:" + filePath);
  var inputfileup = await page.$('#ent_img_file1');
  await inputfileup.uploadFile(filePath);
  await page.waitFor(2000);
  await page.screenshot({path: 'images/blog_edit.png'});

  //ページ遷移
  console.log("page遷移 入力画面→確認画面");
  var inputElement2 = await page.$('center > form > table > tbody > tr:nth-child(14) > th > input[type=button]');
  await inputElement2.click();
  await page.waitFor(2000);
  console.log("page 確認画面");
  await page.screenshot({path: 'images/blog_edit2.png'});

  console.log("page遷移 確認画面→投稿→完了ページ");
  var bottonobj = await page.$('center > form > table > tbody > tr:nth-child(14) > th > input:nth-child(2)');
  await bottonobj.click();

  console.log("page 完了ページ");
  await page.waitFor(3000);
  console.log(page.url());
  await page.screenshot({path: 'images/blog_edit3.png'});

  //クッキーファイルの更新
  const afterCookies = await page.cookies();
  fs.writeFileSync('cookies_masalib_site.json', JSON.stringify(afterCookies));

  //ブラウザのクローズ
  browser.close();

})();



はまった所

初心者レベルで恐縮ですが
リストページの新規作成のボタンを押す事ができなかった
理由はボタンを特定できるセレクタがわからなかった

調べてみるとchromeデベロッパーモードで
対象のセレクタを取得できるようでした

f:id:masalib:20170922212646p:plain

f:id:masalib:20170922212659p:plain

上記のcopy Selectorと選ぶとコピーされる

body > table > tbody > tr > td:nth-child(2) > div > input

bodyはいらないので削除する必要がありました
またinputのあとにタイプも指定しました

table > tbody > tr > td:nth-child(2) > div > input[type=button]


今もできていない所

対象のセレクタがない場合は、

returns: <promise ||<="" になるらしいのですが="" まだその部分を理解できておらず実装できていない="" **="" 今後について="" ・できていない部分をできるようになりたい="" ・imageのダウンロード系をやっていく="" ・ダイアログ系の対応="" ・frameの対応="" まだまだ勉強しないと提案とかは難しいな~="" [asin:b01kpi3ibo:detail]="" <="" content="">
<hatena:formatted-content type="text/html" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"><p>puppeteerを使って記事更新するのをやってみました<br>
ファイルアップもできました<br>
<br>
</p>
<ul class="table-of-contents">
    <li><a href="#概要">概要</a></li>
    <li><a href="#プログラム">プログラム</a></li>
    <li><a href="#はまった所">はまった所</a></li>
    <li><a href="#今もできていない所">今もできていない所</a></li>
    <li><a href="#今後について">今後について</a></li>
</ul>
<div class="section">
    <h4 id="概要">概要</h4>
    <p>記事更新の概要は以下のとおりです<br>
1・ログイン処理<br>
2・リストページ遷移<br>
3・新規追加ボタンを押す<br>
4・新規作成の画面に遷移される<br>
5・新規作成画面で記事内容を投稿する<br>
  テキストボックス、テキストエリア、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C1%A5%A7%A5%C3%A5%AF%A5%DC%A5%C3%A5%AF%A5%B9">チェックボックス</a>、ファイル添付<br>
6・投稿内容の確認画面に遷移する<br>
7・確認画面から完了画面に遷移する</p><p><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-1411576193652714" data-ad-slot="3979960635" data-ad-format="link"></ins><br>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br>
</p>

</div>
<div class="section">
    <h4 id="プログラム">プログラム</h4>
    <p>ログインの処理は前回の処理を参照<br>
<iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Fmasalib.hatenablog.com%2Fentry%2F2017%2F09%2F23%2F000000" title="puppeteerでCMSのログイン処理 - masalibの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="http://masalib.hatenablog.com/entry/2017/09/23/000000">masalib.hatenablog.com</a></cite></p><p></p>
<pre class="code lang-javascript" data-lang="javascript" data-unlink=""><span class="synStatement">const</span> puppeteer = require(<span class="synConstant">'puppeteer'</span>);
<span class="synStatement">const</span> fs = require(<span class="synConstant">'fs'</span>);
<span class="synStatement">const</span> cookies_path = <span class="synConstant">'./cookies_masalib_site.json'</span>;
<span class="synStatement">const</span> loginmodule = require(<span class="synConstant">'./loginWithCookie.js'</span>);

(async () => <span class="synIdentifier">{</span>
  <span class="synStatement">const</span> browser = await puppeteer.launch(<span class="synIdentifier">{</span>
    headless: <span class="synConstant">true</span>,
  <span class="synIdentifier">}</span>);
  <span class="synStatement">const</span> page = await browser.newPage();
  await page.setViewport(<span class="synIdentifier">{</span>width: 1280, height: 700<span class="synIdentifier">}</span>);

  await loginmodule.loginproc(page);
  await page.waitFor(1000);

  <span class="synComment">//一覧ページ</span>
  await page.<span class="synStatement">goto</span>(<span class="synConstant">'http://masalib.jp/admin/blog/ArticleList.asp?page=1'</span>);

  console.log(page.url());
  <span class="synStatement">const</span> inputElement = await page.$(<span class="synConstant">'table > tbody > tr > td:nth-child(2) > div > input[type=button]'</span>);
  await inputElement.click();	<span class="synComment">//新規作成ボタンをクリック</span>
  await page.waitFor(1000);
  console.log(page.url());	<span class="synComment">//新規作成のページに遷移しているの確認</span>


  <span class="synComment">//投稿内容</span>
  <span class="synComment">//テキストボックス</span>
  await page.focus(<span class="synConstant">'input[name=art_title]'</span>);
  await page.type(<span class="synConstant">"art_title_test"</span>);
  await page.focus(<span class="synConstant">'input[name=keyword]'</span>);
  await page.type(<span class="synConstant">"keyword_test"</span>);

  <span class="synComment">//テキストエリア</span>
  await page.focus(<span class="synConstant">'textarea[name=art_nom_text]'</span>);
  await page.type(<span class="synConstant">"art_nom_text_test"</span>);
  await page.focus(<span class="synConstant">'textarea[name=art_text]'</span>);
  await page.type(<span class="synConstant">"art_text_test"</span>);

  <span class="synComment">//チェックボックス</span>
  <span class="synIdentifier">var</span> inputElement2 = await page.$(<span class="synConstant">'center > form > table > tbody > tr:nth-child(2) > td > table > tbody > tr:nth-child(2) > td.data > input[type="checkbox"]'</span>);
  await inputElement2.click();

  <span class="synComment">//ファイルアップ</span>
  <span class="synIdentifier">var</span> filePath =  __dirname + <span class="synConstant">'/icon.jpg'</span>;
  console.log(<span class="synConstant">"filePath:"</span> + filePath);
  <span class="synIdentifier">var</span> inputfileup = await page.$(<span class="synConstant">'#ent_img_file1'</span>);
  await inputfileup.uploadFile(filePath);
  await page.waitFor(2000);
  await page.screenshot(<span class="synIdentifier">{</span>path: <span class="synConstant">'images/blog_edit.png'</span><span class="synIdentifier">}</span>);

  <span class="synComment">//ページ遷移</span>
  console.log(<span class="synConstant">"page遷移 入力画面→確認画面"</span>);
  <span class="synIdentifier">var</span> inputElement2 = await page.$(<span class="synConstant">'center > form > table > tbody > tr:nth-child(14) > th > input[type=button]'</span>);
  await inputElement2.click();
  await page.waitFor(2000);
  console.log(<span class="synConstant">"page 確認画面"</span>);
  await page.screenshot(<span class="synIdentifier">{</span>path: <span class="synConstant">'images/blog_edit2.png'</span><span class="synIdentifier">}</span>);

  console.log(<span class="synConstant">"page遷移 確認画面→投稿→完了ページ"</span>);
  <span class="synIdentifier">var</span> bottonobj = await page.$(<span class="synConstant">'center > form > table > tbody > tr:nth-child(14) > th > input:nth-child(2)'</span>);
  await bottonobj.click();

  console.log(<span class="synConstant">"page 完了ページ"</span>);
  await page.waitFor(3000);
  console.log(page.url());
  await page.screenshot(<span class="synIdentifier">{</span>path: <span class="synConstant">'images/blog_edit3.png'</span><span class="synIdentifier">}</span>);

  <span class="synComment">//クッキーファイルの更新</span>
  <span class="synStatement">const</span> afterCookies = await page.cookies();
  fs.writeFileSync(<span class="synConstant">'cookies_masalib_site.json'</span>, JSON.stringify(afterCookies));

  <span class="synComment">//ブラウザのクローズ</span>
  browser.close();

<span class="synIdentifier">}</span>)();
</pre><p><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-1411576193652714" data-ad-slot="3979960635" data-ad-format="link"></ins><br>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br>
</p>

</div>
<div class="section">
    <h4 id="はまった所">はまった所</h4>
    <p>初心者レベルで恐縮ですが<br>
リストページの新規作成のボタンを押す事ができなかった<br>
理由はボタンを特定できる<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BB%A5%EC%A5%AF%A5%BF">セレクタ</a>がわからなかった</p><p>調べてみると<a class="keyword" href="http://d.hatena.ne.jp/keyword/chrome">chrome</a>の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%D9%A5%ED%A5%C3%A5%D1">デベロッパ</a>ーモードで<br>
対象の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BB%A5%EC%A5%AF%A5%BF">セレクタ</a>を取得できるようでした</p><p><span itemscope="" itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masalib/20170922/20170922212646.png" alt="f:id:masalib:20170922212646p:plain" title="f:id:masalib:20170922212646p:plain" class="hatena-fotolife" itemprop="image"></span></p><p><span itemscope="" itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masalib/20170922/20170922212659.png" alt="f:id:masalib:20170922212659p:plain" title="f:id:masalib:20170922212659p:plain" class="hatena-fotolife" itemprop="image"></span><br>
例<br>
上記のcopy Selectorと選ぶとコピーされる</p>
<pre class="code" data-lang="" data-unlink="">body > table > tbody > tr > td:nth-child(2) > div > input</pre><p>bodyはいらないので削除する必要がありました<br>
またinputのあとにタイプも指定しました</p>
<pre class="code" data-lang="" data-unlink="">table > tbody > tr > td:nth-child(2) > div > input[type=button]</pre><p><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-1411576193652714" data-ad-slot="3979960635" data-ad-format="link"></ins><br>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p>

</div>
<div class="section">
    <h4 id="今もできていない所">今もできていない所</h4>
    <p>対象の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BB%A5%EC%A5%AF%A5%BF">セレクタ</a>がない場合は、</p>
<pre class="code" data-lang="" data-unlink="">returns: <Promise</pre><p>になるらしいのですが<br>
まだその部分を理解できておらず実装できていない</p>

</div>
<div class="section">
    <h4 id="今後について">今後について</h4>
    <p>・できていない部分をできるようになりたい<br>
・imageのダウンロード系をやっていく<br>
・ダイアログ系の対応<br>
・frameの対応</p><p>まだまだ勉強しないと提案とかは難しいな~</p><div class="hatena-asin-detail"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/B01KPI3IBO/amazonmasalib-22/"><img src="https://images-fe.ssl-images-amazon.com/images/I/51UtJhNOnzL._SL160_.jpg" class="hatena-asin-detail-image" alt="東方プロジェクト1?/ 8?7色のThe Puppeteer Alice Margatroid (通常Ver。)Complete Figure" title="東方プロジェクト1?/ 8?7色のThe Puppeteer Alice Margatroid (通常Ver。)Complete Figure"></a><div class="hatena-asin-detail-info"><p class="hatena-asin-detail-title"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/B01KPI3IBO/amazonmasalib-22/">東方プロジェクト1?/ 8?7色のThe Puppeteer Alice Margatroid (通常Ver。)Complete Figure</a></p><ul><li><span class="hatena-asin-detail-label">出版社/メーカー:</span> Griffon Enterprise</li><li><span class="hatena-asin-detail-label">メディア:</span> おもちゃ&ホビー</li><li><a href="http://d.hatena.ne.jp/asin/B01KPI3IBO/amazonmasalib-22" target="_blank">この商品を含むブログを見る</a></li></ul></div><div class="hatena-asin-detail-foot"></div></div><p></p>

</div></hatena:formatted-content>

<category term="puppeteer">

<app:control>
  <app:draft>no</app:draft>
</app:control>