

見よう見まねでトライしてみたスクレイピングをcsv出力しようとしました。  
しかし添付の画像のような出力にしかなりません。  
エラーは特にでていませんが、どこをどう修正すれば良いかご教授いただけたら幸いです。

[code]

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.keys import Keys
    from urllib import request
    from bs4 import BeautifulSoup
    from urllib.parse import urljoin
    import datetime
    import time
    import requests
    import csv
    import pandas as pd
    
    START_DT_STR = '2021-12-01'
    SEARCH_WORD  = 'python'
    PRTIMES_URL  = 'https://prtimes.jp/'
    
    start_dt = datetime.datetime.strptime(START_DT_STR, '%Y-%m-%d')
    
    options=Options()
    options.add_argument("--headless")
    driver=webdriver.Chrome("/Users/tanaka.maru/Desktop/Python/chromedriver",options=options)
    driver.get("https://www.google.com/")
    
    driver = webdriver.Chrome('chromedriver',options=options)
    
    #PR TIMESのトップページを開く
    target_url = 'https://prtimes.jp/'   
    driver.get(target_url)
    
    driver.find_element("xpath",'/html/body/header/div/div[2]/div/input').click()
    
    kensaku = driver.find_element("xpath",'/html/body/header/div/div[2]/div/input')
    kensaku.send_keys(SEARCH_WORD)
    kensaku.send_keys(Keys.ENTER)
    
    cnt = 0
    while True:
        try:
            driver.find_element_by_xpath("/html/body/main/section/section/div/div/a").click()
        except: 
            break
        html = driver.page_source
        soup = BeautifulSoup(html, "html.parser")
        #記事URLを取得(40件ずつ処理)
        articles = soup.find_all(class_='list-article__link')[cnt*40:]
        
        #記事情報を格納する配列
        
        #記事ごとの情報を取得
        for article in articles:
            article_time = article.find(class_='list-article__time')
                    
            #csv関連
            eof_flag = False
            csv_date=datetime.datetime.today().strftime("%Y%m%d")
            csv_file_name = 'prtimes_' + csv_date + '.csv'
            f = open(csv_file_name, 'w', encoding='cp932',errors="ignore")
            writer=csv.writer(f, lineterminator='\n')
            csv_header=["title","sub_title","company","pubulished","category1"]
            writer.writerow(csv_header)
    
            try:
                str_to_dt = datetime.datetime.strptime(article_time.get('datetime'), '%Y-%m-%dT%H:%M:%S%z')
            except:
                try:
                    article_time_cvt = article_time.get('datetime').replace('+09:00', '+0900')
                    str_to_dt = datetime.datetime.strptime(article_time_cvt, '%Y-%m-%dT%H:%M:%S%z')
                except:
                    str_to_dt = datetime.datetime.strptime(article_time.text, '%Y年%m月%d日 %H時%M分')
    
            article_time_dt = datetime.datetime(str_to_dt.year, str_to_dt.month, str_to_dt.day, str_to_dt.hour, str_to_dt.minute)
            
            if article_time_dt < start_dt:
                eof_flag = True 
                break
    
            relative_href = article["href"]
            url = urljoin(target_url, relative_href)
    
            r = requests.get(url)
            html = r.text
            soup = BeautifulSoup(html, "html.parser")
            
            records = []
    
            #記事タイトル
            title = soup.select_one("#main > div.content > article > div > header > h1").text
            
            sub_title_elem = soup.select_one("#main > div.content > article > div > header > h2")
            
            #サブタイトル
    
            if sub_title_elem:
                sub_title = sub_title_elem.text
            else:
                sub_title = ""
                
            company = soup.select_one('#main > div.content > article > div > header > div.release--info_wrapper > div.information-release > div').text
            
            published = soup.select_one('#main > div.content > article > div > header > div.release--info_wrapper > div.information-release > time').text
            
            category1= soup.select_one('#main > div.content > article > dl > dd:nth-child(4) > a:nth-child(1)').text
                    
            records.append({'title':title,'sub_title':sub_title,'company':company,'published':published,'category1':category1})
            
            writer.writerow(records)
    
        if records:
            pass
    
        if eof_flag:
            break
    
        time.sleep(2)  
        cnt += 1
    
        f.close
    
[/code]

[![画像の説明をここに入力](https://i.stack.imgur.com/UrxPE.png)](https://i.stack.imgur.com/UrxPE.png)


CC BY-SA 4.0
2022-08-20T04:26:48.137
90641
2022-08-20T07:24:07.630
2022-08-20T04:42:16.633
3060
54066
question
python csv selenium
Python CSV出力が上手くいきません。


ちなみに私の環境では`while
True:`の直後に`driver.find_element_by_xpath()`で`click()`する処理があると、最初の実行で`exception`による`break`のため何も処理されずに終了しました。  
`try: ... except: break`の処理を`while True:`ループ内の最後に移動させると処理が出来るようになりました。参考までに。

それ以外の主な修正内容は以下になります。

  * 一番の原因は、記事毎のループの中で毎回csvファイルを`'w'`の新規オープン(同じ名前のファイルが既にあれば削除して再作成)しているからです。  
これでは最後の記事一個分のデータだけが入ったファイルしか出来ません。  
csvファイルをオープンするのなら、記事毎のループ`for article in
articles:`の前に行い、また新規では無く`'a'`の追加書き込みでオープンしましょう。

  * `csv`の書き込みオブジェクトを通常の単純テキストの[csv.writer()](https://docs.python.org/ja/3/library/csv.html#csv.writer)にしていますが、記事毎の書き込み処理では辞書データを書き込もうとしているので合っていません。  
[csv.DictWriter()](https://docs.python.org/ja/3/library/csv.html#csv.DictWriter)を使いましょう。  
その場合、ヘッダーを書き込むには[DictWriter.writeheader()](https://docs.python.org/ja/3/library/csv.html#csv.DictWriter.writeheader)を使用します。  
ただしファイルを`'a'`の追加書き込みでオープンしていて、既にデータが存在する場合、常にヘッダーを書き込むと途中の行データとしてヘッダーが追記されてしまうので、ファイルをオープンした直後の何もしていない状態の時に`f.tell()`関数で現在位置を獲得し、それが`0`の時だけヘッダーを書くようにしましょう。

  * 細かいことですが、ヘッダー項目名文字列の中で4つ目の`"pubulished"`はスペルミスしています。正しくは`"published"`でしょう。

  * 記事毎のループ`for article in articles:`の中で、毎回`records`をリストとして初期化`records = []`して、記事から抽出したデータを辞書データとして1件だけ追加`records.append({...})`して、その直後にそのリストをcsvの行データとして書き込んで`writer.writerow(records)`いますが、冗長だったりチグハグだったりします。  
csvへの書き込みと共に後々の処理のためにリストとしても残しておきたいなら、記事毎のループの中で毎回初期化するのは変ですし、記事の件数だけリスト化された辞書データならば、それ全体を毎回csvに書いていては、同じデータが何重にも書き込まれてしまいます。あと複数行(レコード)を書き出すのは`writer.writerows(records)`という最後に`s`が付いた関数を使います。  
現在の1件の記事から抽出したデータをそのまま辞書データとしてリストに追加して、記事毎にそのリスト全体をcsvに書き出す処理は止めて、記事毎に1件の辞書データ`record`を作成し、それを(関数名も変数名も`s`の付かない)`writer.writerow(record)`でcsvに書き込み、リストに残す必要があるなら`records.append(record)`としてcsv書き込みとは別に処理した方が良いでしょう。

  * 記事毎のループ`for article in articles:`の後の`if records:`とその成立時の`pass`の処理が意味不明です。質問記事を書く際の質問事項に関係無い何かの処理が残っているのかもしれません。

  * 記事毎のループ`for article in articles:`の中でcsvファイルを`open()`しているのに、そのループを抜けた`while True:`ループの最後で`f.close()`しているのは、処理のネスト(インデント)レベルが合っていません。  
まあ上記「一番の原因は」の指摘で`open()`は記事毎のループ`for article in
articles:`の前に移動させるので処理のレベルは大丈夫になりますが、まだ`if
eof_flag:`と`break`の処理が前にあるので、最後の記事を処理した後、明確に`f.close()`せずに`while
True:`ループを抜けることになります。  
ということで、`f.close()`は`if eof_flag:`の前に移動しましょう。


CC BY-SA 4.0
2022-08-20T07:24:07.630
90645
2022-08-20T07:24:07.630
26370
90641
answer