質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Puppet

Puppetは、Rubyで作られた UNIX系OSのシステム管理を自動で行うためのツールです。

Q&A

1回答

2308閲覧

[C#] PuppeteerSharpを用いたスクレイピングでの新規ウィンドウが開かれるのを待機する方法

sota1003

総合スコア1

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Puppet

Puppetは、Rubyで作られた UNIX系OSのシステム管理を自動で行うためのツールです。

0グッド

0クリップ

投稿2020/07/17 01:36

編集2020/07/17 02:02

前提・実現したいこと

Node.jsのスクレイピングライブラリのPuppeteerの.NET向けライブラリ「PuppeteerSharp」を用いたツールの作成を行っています。

実現したいこととしては、以下の手順の4番になります。

1.サイトにアクセス
2.いくつかリンクを辿る
3.最後のリンクは新規ウィンドウで開かれる
4.新規ウィンドウに内容が表示されるまで待機
5.HTMLを取得

試したソースコード

下記のソースコードでも成功するときもあれば、見つからないときもある感じです。
成功するとき、失敗するときの違いはイマイチ突き詰めれていません。

C#

1public async Task OpenNewPage() 2{ 3 // リンクをクリック 4 await page.ClickAsync("新規ウィンドウが開かれるリンク"); 5 6 int retryFrequency = 30; 7 int retryInterval = 1000; 8 int retryCount = 0; 9 while (true) { 10 try { 11 // 待機 12 await Task.Delay(retryInterval); 13 // 自分の期待する新規ウィンドウが開かれているか確認 14 newPage = await CheckNewPage(); 15 } catch { 16 if (retryCount++ < retryFrequency) 17 { 18 // 数秒待機してリトライ 19 } else 20 { 21 // リトライ回数オーバー 22 } 23 } 24 } 25 26private async Task<Page> CheckNewPage() 27{ 28 // 開かれているページを全取得 29 var pages = await browser.PagesAsync(); 30 int index = pages.Length - 1; 31 // 最後に開かれたページを取得 32 var newPage = pages[index]; 33 // ページ全てのHTMLを確認し、自分の期待する新規ウィンドウが開かれているか確認 34 while (index >= 0) 35 { 36 // HTML取得 37 string html = await GetHtmlCode(newPage); 38 // 期待する新規ウィンドウかどうか 39 if (html.Contains("特定したい新規ウィンドウ特有と思われる文言")) 40 { 41 return newPage; 42 } 43 else 44 { 45 // 期待する新規ウィンドウでない場合は、1つ前に開かれたページを確認 46 newPage = pages[index--]; 47 } 48 } 49  // 期待するウィンドウは開かれていない 50 throw new Exception(); 51}

(参考)本家Puppeteerでの記述

下記Qiita記事に、Node.jsのPuppeteerでの新規ウィンドウの待機方法が書かれていますが、
これをC#で実行するコードが分かりません。
Puppeteerで次ページへの遷移を待つ

以下、抜粋。

<a href="..." target="_blank">window.open() によるリンクの場合もサブウインドウの場合と考え方は同じですが、遷移後のPageを取り出すのにEventEmitterが絡んでくるので少し複雑になります。
また、この書き方はPuppeteer1.6.0以降が必要です。

javascript

1const newPagePromise = new Promise(resolve => browser.once('targetcreated', 2 target => resolve(target.page()))); 3await page.click('a'); 4const newPage = await newPagePromise; 5await newPage.waitForSelector('input[name="foo"]', {visible: true});

注意点として、target.page()が呼ばれた直後は新ウインドウが作られていてもページ遷移していない可能性があるので、ページ遷移をwaitForSelector()やその他の方法で待つ必要があります。

環境情報

Windows 10 1903
Visual Studio 2017 15.9.24
Microsoft .NET Framework 4.8.03725
Target Framework 4.7.2
PuppeteerSharp 2.0.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

リファレンスを見ながら勘で書いたので「間違っている・もっといい方法がある」かもしれません。

cs

1using System; 2using System.Threading.Tasks; 3using PuppeteerSharp; 4 5namespace Questions278339 6{ 7 class Program 8 { 9 static async Task Main() 10 { 11 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision); 12 var browser = await Puppeteer.LaunchAsync(new LaunchOptions 13 { 14 //Headless = false, 15 }); 16 17 var page = await browser.NewPageAsync(); 18 await page.GoToAsync("https://teratail.com/"); 19 20 // フッターの「teratailを一緒に作りたいエンジニア」リンク 21 var element = await page.WaitForSelectorAsync("#footerTop > div > div.L-footer__navigation.leftCol > div.U-clearfix.clearFix > div > p > a"); 22 await element.ClickAsync(); 23 24 var url = await element.EvaluateFunctionAsync<string>("e => e.getAttribute('href')"); 25 var target = await page.BrowserContext.WaitForTargetAsync((x) => x.Url == url); 26 var page2 = await target.PageAsync(); 27 28 // DOMContentLoadedイベント ClickAsync後 遷移が早いと間に合わないか?? 29 page2.DOMContentLoaded += Page2_DOMContentLoaded; 30 31 // セレクタで待つなら 「応募する」ボタン 32 await page2.WaitForSelectorAsync("body > section > div:nth-child(2) > div.button-area > a"); 33 Console.WriteLine(await page2.GetContentAsync()); 34 35 Console.ReadLine(); 36 browser.Dispose(); 37 } 38 39 private static async void Page2_DOMContentLoaded(object sender, EventArgs e) 40 { 41 if(sender is Page page) 42 { 43 page.DOMContentLoaded -= Page2_DOMContentLoaded; 44 Console.WriteLine(await page.GetContentAsync()); 45 } 46 } 47 } 48}

投稿2020/07/17 12:39

編集2023/07/22 09:22
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問