LoginSignup
3
0

More than 5 years have passed since last update.

スクレイピングの学習 Python3系 その6

Posted at

前回の内容

スクレイピングの学習 Python3系 その5

改善点

  • 元リンクの取得
  • 最終ページの記事が取得出来ていなかったのでループ処理を改修
  • 一覧外のランキング記事などを取得しない
  • タブで分かれたページをすべて取得

手順

  • 一覧部分のdivを一旦取得してから要素を探索
  • 直リンクのURLを取得
  • 次ページ判定のif文を記事取得後に移動
  • 記事取得ループを関数化してタブごとに関数呼び出し

変更・追加したコード

# divタグの中から、class=list_itemの含まれたものを取得(リスト形式になる)
div = soup.find("div", {"class": "content_list"})
tags = div.find_all("div", {"class": "list_item"})

# 抽出した要素を行列に入れ込む
for tag in tags:
    title = tag.find("a", {"class": "title"}).text  # 記事名の取得
    url = tag.find("div", {"class": "comment"}).find("a").get("href")  # リンクの取得
    se = pd.Series([title, url], columns)  # 行を追加

全体のコード

# coding: UTF-8
from selenium import webdriver
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import pandas as pd
import requests
import datetime
import time

# プログラム上からブラウザを操作する
browser = webdriver.Chrome(executable_path="chromedriverのある場所のパス")

# ページ推移用のURL指定(相対URLを絶対URLに変換する用)
originalUrl = "https://newstopics.jp/"
# データフレームを作成。列名 title=記事名, url=url
columns = ["title", "url"]
df = pd.DataFrame(columns=columns)


# 各タブごとに同一の処理を行うため記事の取得を関数化する
def get_article(category):

    # 引数に合わせ、トップページのURLを変更
    url = urljoin(originalUrl, category)
    browser.get(url)  # urlを開く
    page = 1  # ページ数を保存する変数を設定
    global df  # スコープ外で指定した変数の呼び出し

    while True:  # 最終ページまで処理を続ける

        # htmlを取得、BeautifulSoupで扱う
        html = requests.get(url)
        # BeautifulSoupの初期化
        soup = BeautifulSoup(html.content, 'html.parser')
        # 「次へ」を数える
        nextpage = len(soup.find_all("a", {"rel": "next"}))

        # 取得中のページ数を表示
        print("###################page: {} #####################".format(page))
        print("Starting to get posts...")

        # divタグの中から、class=list_itemの含まれたものを取得(リスト形式になる)
        div = soup.find("div", {"class": "content_list"})
        tags = div.find_all("div", {"class": "list_item"})
        # 抽出した要素を行列に入れ込む
        for tag in tags:
            title = tag.find("a", {"class": "title"}).text  # 記事名の取得
            url = tag.find("div", {"class": "comment"}).find("a").get("href")  # リンクの取得
            se = pd.Series([title, url], columns)  # 行を追加
            print(se)  # 行列を表示 <= デバッグ用
            df = df.append(se, columns)  # 新規の行を作成

        if nextpage > 0:  # 次へがある場合の処理
            # 次のページへ移動する
            nextpage_url = soup.find("a", {"rel": "next"}).get("href")  # 次へを探す
            # 相対urlを元urlと組み合わせて絶対urlへ => urlを上書き
            url = urljoin(originalUrl, nextpage_url)
            print("next url:{}".format(url))
            browser.get(url)  # 次ページへジャンプ
            page += 1  # ページ数のインクリメント
            browser.implicitly_wait(10)  # 10秒待機(表示待ちの待機)
            print("Moving to next page......")
            time.sleep(10)  # 10秒待機(サイトへの負荷軽減)

        else:  # 次へがない場合に処理を終了
            print("no pager exist anymore")
            break


get_article("categories/soft")  # ゆるいニュース => categories/soft
get_article("categories/hard")  # かたいニュース => categories/hard

# 重複した内容を削除する
print("Deleting duplicate rows...")
df.drop_duplicates(subset="title", inplace=True)

# CSVに出力
today = datetime.datetime.now().strftime("%y%m%d%H%M%S")  # 今日の日付をファイル名に
filename = today + ".csv"
df.to_csv(filename, index=False, encoding='utf-8')  # encoding指定、おまじない
print("DONE")

# ブラウザを終了する
browser.close()

補足

  • 元リンクへのURLはもともと取得していた部分になかったので、一つ上の要素から取得
  • findを連続で書くのは大丈夫。find_allだとリスト形式になっちゃうので駄目
  • 次ページの有無による判定を前に置いていると、記事の取得前にループを抜けてしまい最終ページの取得ができない
  • タブで別れた部分はurljoinを利用
  • 記事の取得を関数化して、引数に相対URLを指定

次回への課題

  • CSVでダウンロード
  • 重複する内容を取得しないようにする
  • 次ページ以降の取得
  • 元リンクを取得
  • ローカル環境で動かす
  • タブで別れたジャンルをすべて取得
3
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0