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

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

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

Q&A

3回答

949閲覧

【javascript】fetchで複数のページにアクセスし、アクセスした各ページからquerySelectorで要素を取得、その取得した要素を配列にしたい

hosax

総合スコア13

JavaScript

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

0グッド

1クリップ

投稿2022/05/10 16:30

今ご覧いただいているteratailのページを例にお伝えさせていただきます。

ページ下部(「回答する」ボタンの下)の「関連した質問」の各質問のリンク先にfetchでアクセス
質問ぺージの要素(ページのタイトル)をquerySelectorで取得
取得した要素を配列にしたい

記述したコードは以下の通りです。
配列に格納することができず、ご教示いただきたいです。

js

1let questionPageURL = document.querySelectorAll(".question_relatedQuestions__3rsYL .anchor_base__2hAGd"); // 「関連した質問」の各aタグを取得 2let questionPageURLarray = []; // 取得したaタグのhrefを格納する用の空配列を作成 3let questionPageHTMLtitleArray = []; // この後fetchでアクセスするページから取得する要素を格納する空配列を作成 4for (let i = 0; i < questionPageURL.length; i++) { 5 questionPageURLarray[i] = questionPageURL[i].getAttribute("href"); // 取得したaタグからhrefを取得し、ループでquestionPageURLの数だけそれを配列に格納 6 fetch(questionPageURLarray[i]) // fetchで「関連した質問」の各リンク先にアクセス 7 .then((response) => response.text()) 8 .then((text) => { 9 let DOMtext = new DOMParser(); 10 let questionPageHTML = DOMtext.parseFromString(text, "text/html"); 11 let questionPageHTMLtitle = questionPageHTML.querySelector(".questionHeader_title__pUEK0"); // 「関連した質問」のリンク先ページのタイトルを取得 12 questionPageHTMLtitleArray[i] = questionPageHTMLtitle; // 取得したリンク先のタイトルを配列に格納 13 }); 14} 15console.log(questionPageHTMLtitleArray); 16// 結果 [] 17 18// 期待する結果 [h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0, h2.title_base__VKKOr.questionHeader_title__pUEK0]

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

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

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

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

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

guest

回答3

0

setTimeouを活用することで何とか期待の挙動にできました。
int32_t様、yambejp様
お伝えいただいたアドバイスを活かせず申し訳ございません。
非同期処理についてもう少し勉強してみます!

js

1let questionPageURL = document.querySelectorAll(".question_relatedQuestions__3rsYL .anchor_base__2hAGd"); 2let questionPageURLarray = []; 3let questionPageHTMLtitleArray = []; 4function func() { 5 for (let i = 0; i < questionPageURL.length; i++) { 6 questionPageURLarray[i] = questionPageURL[i].getAttribute("href"); 7 fetch(questionPageURLarray[i]) 8 .then((response) => response.text()) 9 .then((text) => { 10 let DOMtext = new DOMParser(); 11 let questionPageHTML = DOMtext.parseFromString(text, "text/html"); 12 let questionPageHTMLtitle = questionPageHTML.querySelector(".questionHeader_title__pUEK0"); 13 questionPageHTMLtitleArray[i] = questionPageHTMLtitle; 14 }); 15 } 16 setTimeout(() => { 17 console.log(questionPageHTMLtitleArray); 18 }, 1000) 19} 20func()

投稿2022/05/12 15:41

hosax

総合スコア13

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

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

hosax

2022/05/12 15:42

もしどなたかPromiseやasync/awaitで実装できるよ!という方法あれば是非ご教示くださいませ。
int32_t

2022/05/12 16:26

setTimeout() だとネットワークやCPUの負荷が高いときに取りこぼしがあります。この方法を使ってはいけません。
guest

0

いかのような感じでどうでしょう?

javascript

1const list=["sample1.html","sample2.html","sample3.html"]; 2list.forEach(x=>fetch(x).then(res=>res.text().then(console.log)));

投稿2022/05/11 01:44

yambejp

総合スコア114829

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

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

hosax

2022/05/11 15:52

アドバイスありがとうございます! ご教示いただいた内容を元にコードを書いたところ、以下のような結果となりました。 ```js let questionPageURL = document.querySelectorAll(".question_relatedQuestions__3rsYL .anchor_base__2hAGd"); let questionPageURLarray = []; let questionPageHTMLtitleArray = []; for (let i = 0; i < questionPageURL.length; i++) { questionPageURLarray[i] = questionPageURL[i].getAttribute("href"); } questionPageURLarray.forEach((questionPageURLarray) => fetch(questionPageURLarray).then((res) => res.text().then((text) => { let DOMtext = new DOMParser(); let questionPageHTML = DOMtext.parseFromString(text, "text/html"); let questionPageHTMLtitle = questionPageHTML.querySelector( ".questionHeader_title__pUEK0" ).innerHTML; questionPageHTMLtitleArray.push(questionPageHTMLtitle); }) ) ); console.log(questionPageHTMLtitleArray); //結果 [] 0: h2.title_base__VKKOr.questionHeader_title__pUEK0 1: h2.title_base__VKKOr.questionHeader_title__pUEK0 2: h2.title_base__VKKOr.questionHeader_title__pUEK0 3: h2.title_base__VKKOr.questionHeader_title__pUEK0 4: h2.title_base__VKKOr.questionHeader_title__pUEK0 5: h2.title_base__VKKOr.questionHeader_title__pUEK0 6: h2.title_base__VKKOr.questionHeader_title__pUEK0 7: h2.title_base__VKKOr.questionHeader_title__pUEK0 length: 8 [[Prototype]]: Array(0) ``` これは配列にはなっていなけれども、値は取得できている?という挙動なのでしょうか、、、 もし何かお気づきのことがございましたらお伝えいただけますと幸いです。 引き続きチャレンジしてみます!
guest

0

then()に渡している関数は非同期に実行されます。forループやconsole.log(questionPageHTMLtitleArray)よりも後に実行されることになります。

Promise.all() ですべての fetch() の完了を待つとか、async await で逐次的に実行しましょう。

投稿2022/05/10 21:21

int32_t

総合スコア20874

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

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

hosax

2022/05/11 00:59

ご教示ありがとうございます! アドバイス頂いた内容を参考に再度チャレンジしてみます!
hosax

2022/05/11 15:04

こちらアドバイスをいただいた内容を元にPromise.all()を利用して以下のように記述したところ、 Uncaught (in promise) TypeError: response.text is not a function at <anonymous>:8:34 とのエラーがでてしまいました。 ```js let questionPageURL = document.querySelectorAll(".question_relatedQuestions__3rsYL .anchor_base__2hAGd"); let questionPageURLarray = []; let questionPageHTMLtitleArray = []; for (let i = 0; i < questionPageURL.length; i++) { questionPageURLarray[i] = fetch(questionPageURL[i].getAttribute("href")); } Promise.all(questionPageURLarray) .then((response) => response.text()) .then((text) => { let DOMtext = new DOMParser(); let questionPageHTML = DOMtext.parseFromString(text, "text/html"); let questionPageHTMLtitle = questionPageHTML.querySelector(".questionHeader_title__pUEK0"); questionPageHTMLtitleArray = questionPageHTMLtitle; }); console.log(questionPageHTMLtitleArray); ``` エラー内容を調べたところ 「Fetchは非同期なので、response.text()を呼び出した時点では、実はまだレスポンスがないのです。response = await fetch を使うか、コールバックを使うか、どちらかです。」 と記述されたページが見つかりましたので、引き続きチャレンジしてみようと思います。 期待する挙動となりましたらご報告させていただきます。 アドバイスありがとうございます! 参考:https://stackoverflow.com/questions/61838276/why-do-i-got-uncaught-typeerror-response-text-is-not-a-function-error-when-try
int32_t

2022/05/12 16:23 編集

> Promise.all(questionPageURLarray) > .then((response) => response.text()) このコードの場合 response は配列になります。 Promise.all(questionPageURLarray) .then(responses => Promise.all(responses.map(response => response.text())) .then(texts => { questionPageHTMLtitleArray = texts.map(text => { return new DOMParser().parseFromString(text, "text/html").querySelector(...); }); console.log(questionPageHTMLtitleArray); }); こんな感じじゃないでしょうか。 async/await の方が簡単だと思います。 g
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問