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

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

ただいまの
回答率

88.91%

Python3 でWebスクレイピングが上手くできません

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 334

takaoioi1

score 1

前提・実現したいこと

Google 検索で上位5つの結果を同時に開く"lucky.py"というプログラムで、'Shohei Ohtani'の検索結果上位5つのWebページを開きたいのですが、うまく実行できません。なお、下記教本を参照しました。

【前提】
バージョン等:Windows10 
Python 3.8 32bit
絶対パス: (以下はインタラクティヴシェルへの入力とその結果です)
>>>os.path.abspath('.')
C:\\Users\\●●●●●\\AppData\\Local\\Programs\\Python\\Python38-32'
(●●●●●は自身のユーザー名、以下同)

【参照】教本のコード
https://github.com/oreilly-japan/automatestuff-ja/blob/master/ch11/lucky.py

【自身の入力コード】

#! python3 

import requests, sys, webbrowser, bs4
print('Googling...')  
res = requests.get('http://google.com/search?q' + ' '.join(sys.argv[1:]))
res.raise_for_status()

soup = bs4.BeautifulSoup(res.text,"html.parser")
link_elems = soup.select('.r a')

num_open = min(5, len(link_elems))
for i in range(num_open):
    webbrowser.open('http://google.com' + link_elems[i].get('href'))

【保存場所・ファイル名その1】
"11-5-lucky.py"というファイル名でデスクトップのPython Scriptフォルダに保存

【コマンドプロンプトでの入力とエラーメッセージ】
C:\Users\●●●●●>Desktop\Python Scripts\11-5-lucky.py
'Desktop\Python' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

("Desktop\Python Scripts\11-5-lucky.py" は自身で入力)

【試したこと】
⓵絶対パスのScriptsフォルダにファイルを保存し再度トライ(ファイル名は単なる'lucky.py'に変更)
(コマンドプロンプトへの入力とエラーメッセージ) 
C:\Users\●●●●●>AppData\\Local\\Programs\\Python\\Python38-32\Scripts\lucky.py 'Shohei Ohtani'
''Shohei' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

⓶py.exe のバッチファイルの作成
@py.exe C:\Users\●●●●●>AppData\\Local\\Programs\\Python\\Python38-32\Scripts\lucky.py %*
というバッチファイルを作り、pythonScripts.bat として下記フォルダに保存
フォルダ名 C:\Users\●●●●●>AppData\\Local\\Programs\\Python\\Python38-32\Scripts
(→ ⓵と同じくコマンドプロンプトに入力:エラーメッセージも出ないが、Web頁も開かれない)
C:\Users\●●●●●>AppData\\Local\\Programs\\Python\\Python38-32\Scripts\lucky.py Shohei Ohtani

C:\Users\●●●●●>

⓷上記⓵⓶について ファイル名を 'lucky.py'から'11-5-lucky.py'に変更
(作業後のコマンドプロンプトのインプットとアウトプット)
C:\Users\●●●●●>AppData\\Local\\Programs\\Python\\Python38-32\Scripts\11-5-lucky.py 'Shohei Ohtani'
Googling...

C:\Users\●●●●●>

(上記⓶同様エラーメッセージも出ないが、Web頁も開かれない)

以上、長々と失礼しますが、よろしくお願いします。
takaoioi1

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Penpen7

    2020/07/04 09:52

    まだうまく行っていません
    ```python #! python3

    ```python
    #! python3
    にして、
    webbrowser.open('http://google.com' + link_elems[i].get('href'))```
    ではなく
    webbrowser.open('http://google.com' + link_elems[i].get('href'))
    ```
    としてください。

    キャンセル

  • Penpen7

    2020/07/06 16:31 編集

    C:\Users\●●●●●>C:\\Users\\●●●●●\\AppData\\Local\\Programs\\Python\\Python38-32 Scripts\11-5-lucky.py
    で実行してみてください。

    キャンセル

  • Penpen7

    2020/07/07 08:33 編集

    Googlingと表示されているということは、pythonスクリプト自体は実行できているということですかね?

    キャンセル

回答 3

checkベストアンサー

0

#! python3

import requests, sys, webbrowser, bs4
print('Googling...')  
res = requests.get('http://google.com/search?q=' + ' '.join(sys.argv[1:]))
res.raise_for_status()
soup = bs4.BeautifulSoup(res.text,"html.parser")
link_elems = soup.select('.kCrYT a')

print(link_elems)
num_open = min(5, len(link_elems))
for i in range(num_open):
    webbrowser.open('http://google.com' + link_elems[i].get('href'))


当方の環境ではこのような形なら動作しました。
憶測で恐縮ですが、例えばGoogleChromeなどで見えるclassとsoupの中のクラス名が同じではないことが原因かと思われます。
一度soupの中身から必要なclass名を取り出してからselectすると良いかと思われます。

以上で今回の問題については解決するかと思われます。
あと
res = requests.get('http://google.com/search?q=' + ' '.join(sys.argv[1:]))q=の部分の=は必要なようなのでお気をつけください。

なお、当方は知りませんでしたが、他の回答者さんにもありますが、googleでは禁止されているようなので、併せてお気をつけください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/09 09:05

    ありがとうございました。解決しましたが、みなさまのおっしゃるとおり、NG事項を事前に調べたうえで、不適切な使用は控えるよう致します。

    キャンセル

0

試したこと2, 3でpythonスクリプトの実行はできていると思われますが、そのあとのselectで該当する要素がないために、link_elemsの中身が空であることが考えられます。
スクレイピング時にはhtmlの構造を観察してどのようにしたら取れるか試行錯誤していきましょう。

そもそも、Googleでの無許可のスクレイピングは禁止されています。
(Google側からアクセスをブロックされる可能性があります)
自動化されたクエリ

Custom Search APIを利用した方が、早いですし、確実です。
Custom Search API
Qiitaの記事

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/07 12:48

    どうしてもスクレイピングしたいなら、Yahoo検索でしょうかね...
    利用規約にもスクレイピングを禁止しているのは見当たらなかったですし、
    robots.txtを見ても大丈夫そうでした。

    キャンセル

0

問題はまずこの行で:

res = requests.get('http://google.com/search?q' + ' '.join(sys.argv[1:]))

'Shohei Ohtani' を入れたら、生成したURLがこうなっています:

'http://google.com/search?qShohei Ohtani'

クエリパラメータのqが正しく生成してませんね。

params引数を用いてこうすればいいです:

res = requests.get('https://google.com/search', params={'q': ' '.join(sys.argv[1:])})

念のためhttpsを用いるようにしました。

ですが、こうしても結果が出てきませんでした。ブラウザーで検索してrクラスを見えるけど、res.textrクラスを見えませんでした。故にこの行は空配列しか返りませんでした。

link_elems = soup.select('.r a')

Googleが検索結果ページをJavaScriptができるかないかによって内容を変わったと思います。これが scraping です、目標サイトの変化に合わせなければならないのです。

クラス名よりURL自身にパッタンがありますか?と思いつつ、検索結果の先頭は全部/urlと発見しました。それを基づいて:

link_elems = [elem for elem in soup.select('a') if elem.get('href').startswith('/url')]

と、結果が出るようになりました。でも最後のURLは検索結果ではなく、GoogleログインのURLなので、無視するようにします:

link_elems = link_elems[:-1]

まとめて、完成したコードはこちら:

#! python3 

import requests, sys, webbrowser, bs4
print('Googling...')  
res = requests.get('https://google.com/search', params={'q': ' '.join(sys.argv[1:])})
res.raise_for_status()

soup = bs4.BeautifulSoup(res.text,"html.parser")
link_elems = [elem for elem in soup.select('a') if elem.get('href').startswith('/url')]
link_elems = link_elems[:-1]

num_open = min(5, len(link_elems))
for i in range(num_open):
    webbrowser.open('https://google.com' + link_elems[i].get('href'))

追記:他の回答に述べた通り、Googleが無断Scrapingを禁止しています。個人的なかつ軽い使い方は多分構いませんが、くれぐれも気をつけてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/09 09:02

    ありがとうございました。解決しましたが、みなさまのおっしゃるとおり不適切な使用は控えます。

    キャンセル

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

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る