Closed corgimkii closed 5 years ago
cheerio-httpcliはブラウザと同じような使い勝手(エンコーディングとかリクエストヘッダは勝手に良い感じにしてくれるので気にしないでいい)でWEBページをスクレイピングできるように、というコンセプトで作られています。
ブラウザのアドレスバーにURLを入力してページにアクセスする際にいきなりPOSTリクエストを飛ばせないのと同じように、cheeroi-httpcliでいきなりPOSTリクエストという機能は今のところは実装していません。
POSTリクエストを送信したい場合は、ブラウザでの操作と同じように、まずPOSTするフォームが設置されているページにfetch()
でアクセスして、そこから$('form').submit()
や$('form input[type=submit]').click()
のような感じでフォーム送信をエミュレートする、という方法を推奨しています。
POSTリクエストを直接送信する方法だと、ある時から送信元のフォームの部品が増えたり減ったり、一部input
のvalue
の内容が変わったりしていた場合、サーバー側が想定していないパラメータを送信してしまう(ありえないパラメータが送信されてきた => ロボットによるアクセスと断定される => 遮断)可能性がありますが、上記の推奨方法ならそういった心配は減ります。
直接POSTリクエストを送信したいケースとして考えられるのは、
などがありますが、
1
に関しては取得する情報がWEBページではなくJSONやXMLになると思うので、むしろcheerio-httpcliを使用しないでrequest
モジュールやfetch
モジュールなど内部で余計な加工を行わないシンプルな通信モジュールを使用した方が良いです(cheerio-httpcliだと内部でエンコーディング変換など行うのでAPIレスポンス内容が壊れる可能性がある)。
2
については、以下のように送信時に動的に作成されるフォーム部品を追加すれば対応可能です。
// 動的にフォーム部品が作成されるページにfetchでアクセス
client.fetch('https://hogehoge.foo/bar.html')
.then(({ $ }) => {
$('form').submit({
query: 'hoge', // 元々存在する項目
new_input1: '12345', // 元々存在しない項目を指定(文字列)
new_input2: [ 'aaa', 'bbb', 'ccc' ] // 元々存在しない項目を指定(配列)
});
});
3
については以下のような感じで対応できます。おそらくいきなりPOST送信するループと同じような形になると思います。
(async () => {
// スリープ関数
const sleep = (n) => new Promise((resolve) => setTimeout(resolve, n));
// フォームが設置されているページにfetchでアクセス
const formPage = await client.fetch('http://hogehoge.foo/bar.html');
// 以下の配列内の文字列を1つずつ指定して同じフォームから送信
const fruits = [ 'apple', 'banana', 'cherry' ];
for (let i = 0; i < fruits.length; i++) {
// result = フォーム送信先ページの情報
const resultPage = await formPage.$('form').submit({
query: fruits[i]
});
// 検索結果を取得
console.log(resultPage.$('h1').text());
// 1秒待機
await sleep(1000);
}
})();
どいった感じで、今のところ直接POSTはなくても良いんじゃないかと思っていますが、POSTリクエストを直接送信したいというシーンを教えてもらっても良いですか。
「なくてもいい」というだけで「あってはならない」というわけではないので、事情を聞いてみて「ああ、それなら直接POSTは必要だなー」ということになれば実装を検討すると思います。
※「なくてもいい」ということは「あってもいい」ということにもなりますが、基本コンセプトが冒頭で述べた通りで、POST送信するにはまず送信したいフォームのページにアクセスするというのが正規の手順だと思いますので、抜け道的な機能は不要であればそれに越したことはない的な感じで考えています。
コンセプトを十分理解せずにissueを上げてしまいすみません。。 やろうとしていることは翻訳サイトにおいて、submit後の翻訳結果画面のスクレイピングです。 (その翻訳サイトでしか提供していない独自の付加機能が必要で、またそのサイトはAPI提供をしていません)
上に挙げて頂いた1.〜3.の中ですと、3.に該当するかと思います。 フォームが設置されている入力画面(GET)は共通ですし、ブラウザのフォーム送信エミュレートと、記載いただいたコード例にて対応可能です! おっしゃるとおり、ブラウザの直接POSTを機能追加するまでもない案件ですね。失礼いたしました。
丁寧にご教示くださり、ありがとうございます。
コンセプトについてはどこかに明記してたわけではないのでお気になさらず。 :wink: 今回は機能追加無しで対応できそうということなので、こちらは閉じさせてもらいます。
いつもWebスクレイピングの用途でcheerio-httpcliを利用させていただいております。 ありがとうございます。
fetch()がGETにて決め打ちになっているため、POSTでアクセスする必要があるページが対象のときは下記のように追記して利用しているのですが、今後、機能追加の予定などはありますでしょうか? もしくは、下記のような形にてプルリクを上げてもよろしいでしょうか?
cheerio-httpcli/index.d.ts
cheerio-httpcli/lib/core.js