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

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

ただいまの
回答率

87.60%

複数の要素のスクレイピングとCSVへの出力について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,497

score 12

前回、Webサイトからのスクレイピング&CSV出力についてご質問をさせていただき、ご回答いただいたお方のお陰で、とりあえずは1つの要素のみCSV出力できるようになったのですが、残りの4つの要素のCSV出力方法が分かりません。調べたところ、取得したい要素をそれぞれ一行で記述する必要があることまでは分かり、いろいろと試しているのですが上手く行きません。
勉強を始めたばかりで頓珍漢なご質問になるかもしれませんが、どうぞよろしくお願いいたします。

○ 情報収集したいサイトは以下になります。
リンク(Bird Fanのサイト)

○ 取得してCSVに展開したい情報
<h2><h3><h4><p><a href=">の5つです。
以下のように1行ずつ書き出し出来るようにしたいです。

=================
フォトギャラリー野鳥図鑑(身近な鳥) (←h2)
身近な鳥(スズメ大)   (←h3)
スズメ          (←h4)
スズメ目ハタオリドリ科  (←p)
全長:14.5cm 翼開長::22.5cm  (←p)
人家付近でのみ見られる。ほおに黒い斑(幼鳥ではうすい)  (←p)
"/pg/kind/ord17/fam1727/spe172702/"  (←a href=" ※フルURL表示でも可)
=================

自分なりに調べて、試行錯誤で以下を実行したのですが、<h4>の情報だけ3行も出力されてしまい行き詰っております。
更に、調べ方が足りないのかもしれませんが<a href=">を出力するコマンド(記述)が分かりません。

mport csv
import requests
import bs4

res = requests.get('https://www.birdfan.net/gallery/library/sanya_mijika.html#01')
res.encoding = res.apparent_encoding
soup = bs4.BeautifulSoup(res.text, "html.parser")
elems = soup.find_all('h2')
elems = soup.find_all('h3')
elems = soup.find_all('h4')
for elem in elems:
 with open(r'C:\Users\8080A\Desktop\bird.csv','w') as csvfile:
    writer = csv.writer(csvfile, lineterminator='\n')
    writer.writerow([str(elem).replace("<h2>","").replace("</h2>","") for elem in elems])
    writer.writerow([str(elem).replace("<h3>","").replace("</h3>","") for elem in elems])
    writer.writerow([str(elem).replace("<h4>","").replace("</h4>","") for elem in elems])

大変恐れ入りますが、どうぞよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

まずh4タグを探してh4タグから上にh2タグ、h3タグを検索
h4タグのすぐ下のpタグを検索してURLを抽出、aタグのテキストが邪魔なので削除

import csv
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

url = 'https://www.birdfan.net/gallery/library/sanya_mijika.html'

headers = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
}

r = requests.get(url, headers=headers)

if r.status_code == requests.codes.ok:

    soup = BeautifulSoup(r.content, 'html5lib')

    with open('result.csv', 'w') as fw:
        writer = csv.writer(fw, dialect='excel', lineterminator='\n')

        for i in soup.select('h4'):

            # h4より上を検索
            h2 = i.find_previous_sibling('h2').get_text(strip=True)
            h3 = i.find_previous_sibling('h3').get_text(strip=True)

            h4 = i.get_text(strip=True)

            # h4より下を検索
            p = i.find_next_sibling('p')
            link = urljoin(url, p.a.get('href'))

            # pのaタグ削除
            p.a.decompose()

            print(h2)
            print(h3)
            print(h4)
            print(p.text.strip())
            print(link)
            print('-' * 20)

            # CSV保存
            writer.writerow([h2, h3, h4, p.text.strip(), link])


結果

フォトギャラリー野鳥図鑑(身近な鳥)
身近な鳥(スズメ大)
スズメ
スズメ目ハタオリドリ科
全長:14.5cm 翼開長:22.5cm
人家付近でのみ見られる。ほおに黒い斑(幼鳥ではうすい)。
https://www.birdfan.net/pg/kind/ord17/fam1727/spe172702/
--------------------
フォトギャラリー野鳥図鑑(身近な鳥)
身近な鳥(スズメ大)
シジュウカラ
スズメ目シジュウカラ科
全長:14cm
白いほお、胸から腹にネクタイ模様(太い方が雄)。
https://www.birdfan.net/pg/kind/ord17/fam1718/spe171805/
--------------------
フォトギャラリー野鳥図鑑(身近な鳥)
身近な鳥(スズメ大)
カワラヒワ
スズメ目アトリ科
全長:14cm
肌色で太めのくちばし、翼と尾に黄色の斑。
https://www.birdfan.net/pg/kind/ord17/fam1724/spe172402/
--------------------

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/10 02:15

    お教えいただきまして誠にありがとうございます。(r.content, 'html5lib')の部分の'html5lib'を'html.parser'に変更して、無事に取得できました。どうもありがとうございます。contentsの中に絞って検索という認識でしたが、あるタグを基準にして上下で分けて検索するという手法もあるのですね。勉強になります。まだ、意味の分からないところが多くありますので、お教えいただいた内容を、調べてみたいと思います。重ねてお礼申し上げます。

    キャンセル

  • 2019/01/10 09:19

    今回はうまくいきましたが参考にされるならcan110さんのプログラムの方がいいように思います。
    自分のは毎回h2とh3を取りにいくので無駄が多いです。

    キャンセル

+1

h2,h3,h4が階層構造になっているので、ソースに表現するのに混乱が見られるようです。
以下のソースを参考に処理を見直してください。

import requests
import bs4
res = requests.get('https://www.birdfan.net/gallery/library/sanya_mijika.html#01')
res.encoding = res.apparent_encoding
soup = bs4.BeautifulSoup(res.text, "html.parser")

section = soup.find(id='contents').find(class_='section')
is_in = False
for tag in section:
    if tag.name == 'h2':
        h2 = tag
    if tag.name == 'h3':
        h3 = tag
    if tag.name == 'h4':
        h4 = tag
        is_in = True

    if is_in and tag.name == 'p': # h4の後のp
        print('-----')
        print('h2',h2.text)
        print('h3',h3.text)
        print('h4',h4.text)
        print('p', tag.text)
        print(tag.a['href'])
        is_in = False

"""
-----
h2 フォトギャラリー野鳥図鑑(身近な鳥)
h3 身近な鳥(スズメ大)
h4 スズメ
p スズメ目ハタオリドリ科
全長:14.5cm 翼開長:22.5cm
人家付近でのみ見られる。ほおに黒い斑(幼鳥ではうすい)。
スズメについて詳しくはこちらをご参照ください
/pg/kind/ord17/fam1727/spe172702/
-----
h2 フォトギャラリー野鳥図鑑(身近な鳥)
h3 身近な鳥(スズメ大)
h4 シジュウカラ
p スズメ目シジュウカラ科
全長:14cm
白いほお、胸から腹にネクタイ模様(太い方が雄)。
シジュウカラについて詳しくはこちらをご参照ください
/pg/kind/ord17/fam1718/spe171805/
 :
"""

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/10 02:01

    お教えいただきまして誠にありがとうございます。何となくですが、部分的に少しだけ理解できたような気がします。ですが、まだ意味が分からない部分が結構あり、自分なりに調べてみたいと思います。
    本当にどうもありがとうございます。

    キャンセル

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

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

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