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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

2574閲覧

pythonのスクレイピングでデータが取得できない

onosan

総合スコア59

スクレイピング

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2020/07/28 08:38

編集2020/07/28 12:15

Python初心者ですみません。あるウェブサイトから、情報を一気に取得したいのですが、ウェブページに多彩なメニューがあり、これら全てを一気に取得する方法などあるでしょうか。
スクレイピングの基本だと思うのですが、ご支援いただけますと幸いです。

ウェブページは以下のものです。

https://nintei.nurse.or.jp/certification/General/(X(1)S(efl0y555pect3x45oxjzfw3x))/General/GCPP01LS/GCPP01LS.aspx?AspxAutoDetectCookieSupport=1

以前に試した方法として、以下のようなものをテンプレートにしているのですが、エラーは起きないのですが、うまく取得できません。

Python3

1 2#保存用 3 4driver_path = r'C:\Anaconda3\chromedriver.exe'#自分のChoromedriverの場所 5 6#読み込みたいフォルダの場所 7URL = 'https://nintei.nurse.or.jp/certification/General/(X(1)S(efl0y555pect3x45oxjzfw3x))/GCPP01LS/GCPP01LS.aspx' 8 9#格納したいフォルダの場所 10send_path = r'C:\Users\akira\Documents\Python\会社' 11 12 13 14from selenium import webdriver 15import time 16import bs4 17import re 18import os 19import time 20import shutil 21from selenium.webdriver.support.ui import WebDriverWait 22from selenium.webdriver.support import expected_conditions as EC 23from selenium.webdriver.common.by import By 24 25start = time.time() 26 27 28driver = webdriver.Chrome(driver_path) 29driver.get(URL) 30time.sleep(3) 31 32soup = bs4.BeautifulSoup(driver.page_source, 'html5lib') 33 34base = 'https://nintei.nurse.or.jp/certification/General/' 35 36soup_file1 = soup.find_all('a') 37href_list = [] 38 39file_num = 1 40sum_file = 1 41 42cc = 0 43for s in soup_file1: 44 if s.string=='検索': 45 path = base+s.get('href') 46 href_list.append(path) 47 48 print(path) 49 driver.get(path) 50 51 WebDriverWait(driver, 300).until(EC.element_to_be_clickable((By.XPATH,'//*[@id="ctl00_plhContent_btnSearchMain"]'))) 52 driver.find_element_by_xpath('//*[@id="ctl00_plhContent_btnSearchMain"]').click() 53 54 while sum_file == file_num : 55 sum_file = len(os.listdir(r'C:\Users\akira\Downloads')) 56 57 else: 58 print("現在のダウンロードファイル数_{}枚".format(sum_file-1)) 59 file_num += 1 60 61 cc += 1 62 63 64#一時ファイルが邪魔をする場合があるので時間を少し開ける 65time.sleep(60) 66 67 68#ファイルの移動 69 70 71dw_path = r'C:\Users\akira\Documents\Python\会社' 72dw_list = os.listdir(dw_path) 73 74dw_xlsx = [f for f in dw_list] 75for dw in dw_xlsx: 76 shutil.move(r'C:\Users\akira\Documents\Python\会社')

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

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

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

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

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

tetuhiroshi

2020/08/01 07:15

具体的には、どのようなことをするプログラムなのでしょうか。 詳しく書いていただけると、助かります。
onosan

2020/08/02 08:09

ご連絡がおそくなってしまいすみません。当初は、一括で看護師やその関係者を一括でダウンロードするようなプログラムを考えていたのですが、どうも一括でダウンロードするのは難しそうだという感触を得ていて、そうであればある程度分割してでも、このページの情報を全てエクセルなどにダウンロードする方法はないかと検討している次第です。当方、pandasなどは勉強しているのですがスクレイピングの知識が圧倒的に欠落していて、どのように手をつければよいのか困り果てているところです。 ご協力いただけますと幸いです。
tetuhiroshi

2020/08/02 08:18

ページの情報すべてというのは、認定看護師の資格を持つ方のリストを、条件指定をせずにすべて取得する、ということでしょうか?
onosan

2020/08/02 08:27

ご連絡ありがとうございます。当初言われたのは、認定看護師、認定看護管理者、専門看護師全てということだったのですが、かなり難しそうなので、認定看護師全てにさせていただければと思います。それが、わかれば、認定看護管理者と専門看護師全ても応用でできるのではないかと思います。 重ねて、ご協力いただけますと幸いです。
guest

回答2

0

ベストアンサー

先にお送りしたプログラムは、捨ててしまってください。
データを一部ダウンロードできない不具合がありました。

そして、これでどうでしょうか?

お試しでデータをダウンロードするか(400件のみ)・
データの内容を逐一表示するか・ダウンロードの進捗を表示するか
<- TEST, DATA_DISPLAY, PROGRESS_DISPLAY

の、3つのフラグと、

どの資格区分のデータをダウンロードするか
<- QUALIFICATION

のオプションをつけておきました。

とりあえず、PROGRESS_DISPLAYとTESTをTrueにして、動かしてみてください。

python3

1INTERVAL = 0.5 # アクセスの間隔(1.5秒以上が好ましい) 2 3TEST = True # テスト用データを取得するか(本番ではFalseに設定) 4DATA_DISPLAY = True # データの内容を逐一確認するか 5PROGRESS_DISPLAY = True # 進捗を表示するか 6 7# "認定看護師" "認定看護管理者" "専門看護師"のいずれかを入力 8QUALIFICATION = "認定看護師" 9 10 11from bs4 import BeautifulSoup 12from selenium import webdriver 13import re 14import time 15import pandas 16 17prefectures = ["北海道", "青森県", "岩手県", "宮城県", "福島県", "秋田県", "山形県", "新潟県", "富山県", "石川県", "福井県", "長野県", "岐阜県", "山梨県", "静岡県", "愛知県", "茨城県", "千葉県", "栃木県", "埼玉県", "東京都", "神奈川県", "群馬県", "滋賀県", "三重県", "京都府", "奈良県", "兵庫県", "大阪府", "和歌山県", "鳥取県", "島根県", "山口県", "岡山県", "広島県", "香川県", "愛媛県", "徳島県", "高知県", "福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"] 18 19# 結果を格納する辞書 20result = list() 21 22# 分野別都道府県別検索のサイト 23url = "https://nintei.nurse.or.jp/certification/General/(X(1)S(efl0y555pect3x45oxjzfw3x))/General/GCPP01LS/GCPP01LS.aspx?AspxAutoDetectCookieSupport=1" 24 25# ドライバーでサイトにアクセスする 26driver = webdriver.Chrome() 27driver.get(url) 28 29if QUALIFICATION == "認定看護師": 30 button = "#ctl00_plhContent_radlstCert_0" 31 32elif QUALIFICATION == "認定看護管理者": 33 button = "#ctl00_plhContent_radlstCert_1" 34 35elif QUALIFICATION == "専門看護師": 36 button = "#ctl00_plhContent_radlstCert_2" 37 38# 資格区分に応じたページに移動 39driver.find_element_by_css_selector(button).click() 40 41# 検索ボタンを押して一覧を表示する 42driver.find_element_by_css_selector("#ctl00_plhContent_btnSearchMain").click() 43 44while True: 45 46 # ページ取得の間隔をあける 47 time.sleep(INTERVAL) 48 49 # ページのソースを取得する 50 source = driver.page_source 51 52 # ページのソースからBeautifulSoupオブジェクトを生成する 53 soup = BeautifulSoup(source, "html.parser") 54 55 # trタグを持つ要素のリストを取得する 56 rows = list(soup.find_all("tr")) 57 58 # trタグを持つ要素のリストから、資格別のリストを抽出する 59 for row in rows: 60 if len(list(row)) == 7 and list(row)[2].string in prefectures: 61 person = dict() 62 person["分野"] = list(row)[1].string 63 person["都道府県"] = list(row)[2].string 64 person["氏名"] = list(row)[3].string 65 person["施設法人名"] = list(row)[4].string 66 person["所属先施設名"] = list(row)[5].string 67 # 情報をディクショナリに追加する 68 result.append(person) 69 70 if DATA_DISPLAY: 71 print(person) 72 73 # 全件数中、何件検索したかを取得し、表示する 74 info = soup.select_one("html body form#aspnetForm div#container div table#ctl00_plhContent_dlvMain.list_table tbody tr td div#page_navi_wrapper.clearfix ul.page_navi li.pagetotal").text 75 if PROGRESS_DISPLAY: 76 print(info + "・取得済み") 77 print("\n") 78 79 # もし最後のページならスクレイピングを終了する 80 match_result = re.match("[0-9]+~([0-9]+)件目/([0-9]+)件", info) 81 if match_result.group(1) == match_result.group(2): 82 break 83 84 # もしTESTフラグがオンなら400件目までテスト用に取得する 85 if int(match_result.group(1)) >= 400: 86 break 87 88 # 最後のページでないなら、次のページに移動する 89 driver.find_element_by_xpath('//a[text()="[次]"]').click() 90 91# ファイル名を生成する 92file_name = "{}{}一覧.xlsx".format("テスト" if TEST else "", QUALIFICATION) 93print(file_name + "に書き出し中") 94 95# スクレイピングの結果をエクセルファイルに落とし込む 96df = pandas.DataFrame(result) 97df.to_excel(file_name, encoding="cp932", index=False)

投稿2020/08/03 07:43

編集2020/08/03 08:03
tetuhiroshi

総合スコア46

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

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

onosan

2020/08/03 12:03

tetuhiroshi様 ご連絡が遅くなりすみません。 バリデーションをして、確かに全てダウンロードできることが確認できました。 すばらしいです。もしよろしければ、この回答をする上で、あるいはどのようなサイトがスクレイピングの勉強になるか、ご教示いただけますと幸いです。 というのも、どうしてこれでうまくいくのか、まだ分からず、研究したいと考えております。 会社のPythonに詳しい人にも聞いてみますが、すばらしい力をお持ちですね。 本当に助かりました。ありがとうございます。
tetuhiroshi

2020/08/03 13:34 編集

seleniumはたしかに難しいと思います。 私もまだ読みやすくシンプルなプログラムはかけません。 こういうちょっと難しめな技術(複雑というか)を習得するにはやはり基本が一番だと思います。 インターネット上の散文的な情報を頼りにするのもいいですが、seleniumの公式サイトにある ドキュメント(https://www.selenium.dev/documentation/en/)を一通り、 (できたら原文で!)試してみて、その上で一つでいいので、自分だけの ソフトかなんかを作ってみると上達につながるのではないでしょうか。 公式ドキュメント英語で全部かーい!と言いたくなりますが、正規表現などと一緒で、 ここで時間をかけて自分に投資しておくと、あとで何倍ものお釣りとなってかえってくるはずです。 応援しています!
guest

0

サイトの仕様に合わせて書いたので、あまり汎用性はありませんが、
このようなコードはいかがでしょうか?

python3

1# スクレイピング時のマナーとして、サーバーに負担をかけない、 2# というものがあります。 3# そのため、ページ取得の間隔を2秒間に設定しています。 4# この場合、データの取得に11時間ほどかかりますが、これを短縮する 5# としても、2秒を1.5秒に縮める程度に抑えることが 6# 相手方への配慮として必要とご理解ください 7 8interval = 2 9 10DATA_DISPLAY = False 11 12from bs4 import BeautifulSoup 13from selenium import webdriver 14import re 15import time 16 17prefectures = ["北海道", "青森県", "岩手県", "宮城県", "福島県", "秋田県", "山形県", "新潟県", "富山県", "石川県", "福井県", "長野県", "岐阜県", "山梨県", "静岡県", "愛知県", "茨城県", "千葉県", "栃木県", "埼玉県", "東京都", "神奈川県", "群馬県", "滋賀県", "三重県", "京都府", "奈良県", "兵庫県", "大阪府", "和歌山県", "鳥取県", "島根県", "山口県", "岡山県", "広島県", "香川県", "愛媛県", "徳島県", "高知県", "福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"] 18 19# 結果を格納する辞書 20result = list() 21 22# 認定看護師のサイト 23url = "https://nintei.nurse.or.jp/certification/General/(X(1)S(efl0y555pect3x45oxjzfw3x))/General/GCPP01LS/GCPP01LS.aspx?AspxAutoDetectCookieSupport=1" 24 25# ドライバーでサイトにアクセスする 26driver = webdriver.Firefox() 27driver.get(url) 28 29# 認定看護師医師欄のページに移動する 30driver.find_element_by_css_selector("#ctl00_plhContent_btnSearchMain").click() 31 32while True: 33 34 # スクレイピングのマナーとして、ページ取得に一秒以上の間隔をあける 35 time.sleep(interval) 36 37 # ページのソースを取得する 38 source = driver.page_source 39 40 # ページのソースからBeautifulSoupオブジェクトを生成する 41 soup = BeautifulSoup(source, "html.parser") 42 43 # trタグを持つ要素のリストを取得する 44 rows = list(soup.find_all("tr")) 45 46 # trタグを持つ要素のリストから、看護師のリストを抽出する 47 for row in rows: 48 if len(list(row)) == 7 and list(row)[2].string in prefectures: 49 person = dict() 50 person["分野"] = list(row)[1].string 51 person["都道府県"] = list(row)[2].string 52 person["氏名"] = list(row)[3].string 53 person["施設法人名"] = list(row)[4].string 54 person["所属先施設名"] = list(row)[5].string 55 # 看護師の情報をディクショナリに追加する 56 result.append(person) 57 58 # 全件数中、何件検索したかを取得し、表示する 59 info = soup.select_one("html body form#aspnetForm div#container div table#ctl00_plhContent_dlvMain.list_table tbody tr td div#page_navi_wrapper.clearfix ul.page_navi li.pagetotal").text 60 print(info) 61 62 # もし最後のページならスクレイピングを終了する 63 match_result = re.match("[0-9]+~([0-9]+)件目/([0-9]+)件", info) 64 if match_result.group(1) == match_result.group(2): 65 break 66 67 # 最後のページでないなら、次のページに移動する 68 driver.find_element_by_css_selector("#ctl00_plhContent_dlvMain > tbody:nth-child(1) > tr:nth-child(53) > td:nth-child(1) > div:nth-child(1) > ul:nth-child(1) > li:nth-child(9) > a:nth-child(1)").click() 69 70# スクレイピングの結果 71print(result)

whileループの中のperson変数を使ってexcelデータに落とし込んだり、
ループ終了後のresult変数から新しくファイルを作ったりとできるはずです。
データが取得できているか逐一確認したいときは、DATA_DISPLAYフラグを
Trueにして実行してみてください。

このコードのままだと、取得後データを表示して終わってしまうので、
関数にして使っていただくといいと思います。

投稿2020/08/02 22:18

tetuhiroshi

総合スコア46

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

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

onosan

2020/08/03 02:17 編集

tetuhiroshi様 ご回答ありがとうございます。 firefoxが使えない環境のため、Chromeにして、BeautifulSoapのバージョンを上げたところ、 動きました。 最後に来て、 IOPub data rate exceeded. The notebook server will temporarily stop sending output to the client in order to avoid crashing it. To change this limit, set the config variable `--NotebookApp.iopub_data_rate_limit`. Current values: NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec) NotebookApp.rate_limit_window=3.0 (secs) となってしまいましたが、これは、おっしゃるようにサーバに負荷がかかっているのかもしれません。 こちら、コードのどの部分を直せばよいのか分からずと言う感じです。 すごく前進していて、とても助かっております。 大変恐れ入りますが、今一度お知恵を拝借できればと思います。 宜しくお願い申し上げます。
onosan

2020/08/03 02:34

tetuhiroshi様 すみません。自己解決しました。 最後のprintをやめて、下記のようにDataFrameにすることで、エクセルに落ちました。 現状、看護師なのですが、認定看護管理者にするには、 driver.find_element_by_css_selector("#ctl00_plhContent_btnSearchMain").click() を変えれば良さそうなのですが、こちら、どこを見ればよいか真に恐れ入りますが、 ご教示を賜れないでしょうか。 重ねて恐れ入ります。 何卒、よろしくお願い申し上げます。 import pandas as pd df = pd.DataFrame(result) df.to_excel("看護師.xlsx",encoding="cp932",index=False)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問