

Ubuntu＋Python＋SeleniumでChromeを自動化し、Saveボタンをクリックしてファイルをローカルに保存するところまで出来ましたが、このファイル名が手動で制御出来ず、取得元のサイトが検索ワードに基づいて付けた適当な名前になります。  
この、たった今保存されたファイルのファイル名をPythonで取得する場合、どの方法が賢いでしょうか。  
ディレクトリを検索し、正規表現でファイル名に合致したリストを得て、最も新しいものがそれだ、というのを考えましたが、たぶんあるあるの事例だと思いますので、より良い方法がありましたらご教示くだされば幸いです。


CC BY-SA 4.0
2021-06-24T09:33:01.397
77760
2021-06-25T11:55:53.573
26673
question
python ubuntu google-chrome selenium selenium-webdriver
Seleniumで取得保存したファイル名の特定


> Ubuntu＋Python＋Selenium

ご質問の前提条件から外れてしまいますが、 Selenium ではなく [Puppeteer](https://pptr.dev/)
であれば、直接ダウンロードするパスとファイル名を指定する方法があります。  
→ [puppeteer でファイルをダウンロードするときに、任意のパスと名前で保存する | Aqua Ware
つぶやきブログ](https://aquasoftware.net/blog/?p=1583)

上記の記事は、 node.js + Puppeteer の例ですが、
[pyppeteer](https://github.com/pyppeteer/pyppeteer) を使うことで、以下のように Python
でも同様の結果が得られます。

[code]

    import os
    import asyncio
    
    # Fetch.enable に対応している Chromeimum リビジョンを指定
    os.environ['PYPPETEER_CHROMIUM_REVISION'] = '884014'
    import pyppeteer
    
    event_loop = asyncio.get_event_loop()
    
    async def main(file_name, headless=True, wait_time=5.0):
        b = await pyppeteer.launch({'headless': headless})
        p = await b.newPage()
        await p.goto('https://github.com/pyppeteer/pyppeteer')
        e = await p.querySelector('get-repo')
        await e.click()
    
        client = await p.target.createCDPSession()
        await client.send('Page.setDownloadBehavior', { 'behavior': 'allow', 'downloadPath': os.getcwd() })
        await client.send('Fetch.enable', { 'patterns': [ { 'urlPattern': '*', 'requestStage': 'Response' }] })
    
        async def onRequestPaused(requestEvent):
            responseHeaders = [v for v in requestEvent['responseHeaders'] if v['name'] != 'content-disposition']
            requestId = requestEvent['requestId']
            if requestEvent['responseStatusCode'] == 200:
                responseHeaders.append({ 'name': 'content-disposition', 'value': f'attachment; filename="{file_name}"'})
                response = await client.send('Fetch.getResponseBody', { 'requestId': requestId })
                await client.send('Fetch.fulfillRequest', { 'requestId': requestId, 'responseCode': 200, 'responseHeaders': responseHeaders, 'body': response['body'] })
            else:
                await client.send('Fetch.continueRequest', { 'requestId': requestId }); 
        client.on('Fetch.requestPaused', lambda e: asyncio.ensure_future(onRequestPaused(e), loop=event_loop))
    
        # Github の "Download ZIP" のボタンをクリック
        e = await p.querySelector('a[href$=".zip"]')
        await e.click()
        await asyncio.sleep(wait_time)
        await client.send('Fetch.disable')
        await b.close()
    
    event_loop.run_until_complete(main(file_name='specified_name.zip', headless=False))
    
[/code]

Windows および WSL 上の Ubuntu で動作確認済みです。

pyppeteer のオリジナルが node.js であることから、基本非同期な API となっているため、 Selenium の同期的な API
に慣れていると、扱いづらいとは思います。  
参考になれば。


CC BY-SA 4.0
2021-06-24T19:37:32.033
77766
2021-06-24T19:42:55.383
2021-06-24T19:42:55.383
8237
8237
77760
answer


コメントでお示しいただいた、以下の記事を参考に解決しました。

[Python Selenium
動的なダウンロード完了待機](https://qiita.com/hajimejimejime/items/58949dc18b52ae926b1b)

実は表題の問題の他に、ダウンロードの終了を関知できないという問題もあったのですが、同時に解決してハッピーです。  
拙ソースを掲げます。

守秘義務の関係でぼかしていますが、以下の条件とします。

  * `https://foo.example.com/` というサイトを検索する
  * barbarbar、bazbazbazというワードで検索する
  * 検索結果はfoo_search_*.txtという名前で保存される（*の部分はbarbarb~1のような、検索ワードを元にした短縮した名前になるようだ？）

プログラムの要点は以下の通りです。

  * glob.glob関数を使って、foo_search_*.txt.crdownloadというファイルがあるかぎり、１秒待ちながらループする
  * ループの中で、foo_search_*.txt.crdownloadから.crdownloadを削除してファイル名を得る
  * ループを脱出した場合は、ダウンロードが終わったか、そもそもダウンロードが行えなかったかであるので、適当に処理する

[code]

    #! /usr/bin/python3
    import glob 
    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By # for find_element_by_ID
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions
    from selenium.webdriver.common.keys import Keys
    
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    driver = webdriver.Chrome(options=options) 
    wait = WebDriverWait(driver, 10) # wait.untilの秒数の上限
    driver.get('https://foo.example.com/') # 検索サイト
    print(driver.title)
    
    def search_and_save(search_term):
        element = 
        wait.until(expected_conditions.visibility_of_element_located((By.ID, "search_term_id"))) # 検索ボックスが表示されるのを待つ
        element.send_keys(Keys.CONTROL + "a")
        element.send_keys(Keys.DELETE)
        element.send_keys(search_term) # 検索ワードを入力してサブミット
        element.submit()
        driver.find_element_by_class_name("search-submit").click()
        new_file = 'ERROR' + search_term # ダウンロードするファイル名、最初はエラー名にしておく
        for i in range(30): # MAX30秒待つ
            download_fileName = glob.glob(f'foo_search_*.txt.crdownload') # crdownloadを探す
            if download_fileName: # crdownloadがあれば
                new_file = download_fileName[0].replace('.crdownload', '') # crdownloadを削除したものでnew_fileを置き換える
                time.sleep(1) # 1秒待つ
            else: # crdownloadがない。downloadが終わったかそもそも始まってなかった
                break
           print('new_file:' + new_file) # ダウンロードが正常に終わっていればそのファイル名が、ダウンロードされていなければファイル名が入る
    
    search_and_save('barbarbar')
    search_and_save('bazbazbaz')
    driver.quit()
    
[/code]


CC BY-SA 4.0
2021-06-25T03:09:51.990
77775
2021-06-25T11:55:53.573
2021-06-25T11:55:53.573
3060
26673
77760
answer