PythonでJavaScriptWebサイトをスクレイプする方法は?

Sep 06 2020

私はウェブサイトをこすり取ろうとしています。2つの方法を使用してみましたが、どちらも探している完全なWebサイトのソースコードを提供していません。下記のウェブサイトのURLからニュースタイトルを取得しようとしています。

URL:「https://www.todayonline.com/」

これらは私が試したが失敗した2つの方法です。

方法1:美しいスープ

tdy_url = "https://www.todayonline.com/"
page = requests.get(tdy_url).text
soup = BeautifulSoup(page)
soup  # Returns me a HTML with javascript text
soup.find_all('h3')

### Returns me empty list []

方法2:セレン+ BeautifulSoup

tdy_url = "https://www.todayonline.com/"

options = Options()
options.headless = True

driver = webdriver.Chrome("chromedriver",options=options)

driver.get(tdy_url)
time.sleep(10)
html = driver.page_source

soup = BeautifulSoup(html)
soup.find_all('h3')

### Returns me only less than 1/4 of the 'h3' tags found in the original page source 

助けてください。私は他のニュースウェブサイトをスクレイピングしようとしました、そしてそれはとても簡単です。ありがとうございました。

回答

2 politicalscientist Sep 06 2020 at 15:38

APIを介してデータにアクセスできます([ネットワーク]タブを確認してください)。


例えば、

import requests
url = "https://www.todayonline.com/api/v3/news_feed/7"
data = requests.get(url).json()
2 Noname Sep 06 2020 at 15:39

Javascriptを含むWebページのコンテンツを収集する方法はいくつかあります。

  1. seleniumFirefoxWebドライバーでの使用
  2. ヘッドレスブラウザを使用して phantomJS
  3. RESTクライアントまたはPythonrequestsライブラリを使用してAPI呼び出しを行う

あなたは最初にあなたの研究をしなければなりません

2 MananGajjar Sep 06 2020 at 16:04

かなり単純なアプローチをお勧めします。

import requests
from bs4 import BeautifulSoup as bs

page = requests.get('https://www.todayonline.com/googlenews.xml').content
soup = bs(page)
news = [i.text for i in soup.find_all('news:title')]

print(news)

出力

['DBS named world’s best bank by New York-based financial publication',
 'Russia has very serious questions to answer on Navalny - UK',
 "Exclusive: 90% of China's Sinovac employees, families took coronavirus vaccine - CEO",
 'Three militants killed after fatal attack on policeman in Tunisia',
.....]

また、必要に応じて、XMLページで詳細を確認できます。

PS Webサイトを廃棄する前に、常にコンプライアンスを確認してください:)

2 DemianWolf Sep 06 2020 at 16:00

スクレイプしようとしているWebサイトのニュースデータは、JavaScriptを使用してサーバーからフェッチされます(これはXHR --XMLHttpRequestと呼ばれます)。ページの読み込み中またはスクロール中に動的に発生します。したがって、このデータはサーバーから返されたページ内には返されません。

最初の例では、サーバーから返されたページのみを取得しています。ニュースはありませんが、JSを使用して取得することになっています。リクエストもBeautifulSoupもJSを実行できません。

ただし、Pythonリクエストを使用して、サーバーからニュースタイトルを取得しているリクエストを再現することはできます。次の手順を実行します。

  1. ブラウザのDevToolsを開き(通常はF12またはCtrl+ Shit+を押す必要がありますI)、サーバーからニュースタイトルを取得しているリクエストを確認します。場合によっては、BeautifulSoupを使用したWebスクレイピングよりも簡単なこともあります。これがスクリーンショット(Firefox)です:
  1. リクエストリンクをコピーし(右クリック->コピー->リンクのコピー)、に渡しrequests.get(...)ます。

  2. .json()リクエストを取得します。扱いやすい辞書が返されます。dictの構造をよりよく理解するためpprintに、単純な印刷の代わりに使用することをお勧めします。from pprint import pprint使用する前に行う必要があることに注意してください。

ページのメインニュースからタイトルを取得するコードの例を次に示します。

import requests


nodes = requests.get("https://www.todayonline.com/api/v3/news_feed/7")\
        .json()["nodes"]
for node in nodes:
    print(node["node"]["title"])

キャプションの下にあるニュースのグループをスクレイプする場合news_feed/は、リクエストURLの後にある番号を変更する必要があります(取得するには、DevToolsの「news_feed」でリクエストをフィルタリングし、ニュースページを下にスクロールするだけです)。

Webサイトがボットから保護されている場合があります(ただし、スクレイプしようとしているWebサイトには保護されていません)。このような場合は、これらの手順も実行する必要があります。