83014


## 実現したいこと

下記のページをスクレイピングして「動画総合」ジャンルの1位のタイトルを取得したいです。

そのためには年齢認証ページを通過する必要があるのですが、そのページの表示可否を決めているcookieの値が毎日変化するようで、プログラムに直書きすると翌日には動かなくなってしまいます。（ソースは「試したこと」の「その1」を参照）

他に２パターン試しましたが、それもうまくいきませんでした。  
年齢認証ページを通過して目的のページに到達できる方法をご教授いただけませんでしょうか？

なお、sudo権限のないレンタルサーバーで動作させるため、Seleniumは使えません。  
以上、よろしくお願いいたします。

##### スクレイピングしたいページのURL

ttps://dgpot.com/product_list.php/cPath/254

##### 年齢認証ページのURL

ttps://dgpot.com/age_check.php/continue/aHR0cHM6Ly9kZ3BvdC5jb20vcHJvZHVjdF9saXN0LnBocC9jUGF0aC8yNTQ

## 試したこと

##### その1

この方法で初日はうまくいったが、年齢認証ページの表示可否を決めているcookieの値が毎日変化するようで、プログラムに直書きすると翌日には年齢認証を通過できなくなる。

[code]

    import requests
    from bs4 import BeautifulSoup
    
    # URLの指定        
    url = 'https://dgpot.com/product_list.php/cPath/254'
    #ユーザーエージェントの設定
    headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"}
    # ここでcookieを指定(このosCsidがクッションページの表示可否を決めている)
    cookie = {'osCsid': 'kbqd914a7vdqrqa7sv31pkpa06'}  
    
    #htmlの取得
    response = requests.get(url=url, headers=headers, cookies=cookie)
    html = response.content
    #BeautifulSoupで扱えるようにパース
    soup = BeautifulSoup(html, "html.parser")
    
    #タイトルを取得してprint
    elems = soup.select("[class='modern_item_list-title'] a")
    for elem in elems:
        print(elem.text)
    
[/code]

##### その2

年齢認証ページは通過でき、成人向け総合の２位までは取得できるが、それ以降がなぜか取得できない。

[code]

    import requests
    from bs4 import BeautifulSoup
    
    #クッションページの「はい」ボタンのurl
    yes_button_url = 'https://dgpot.com/age_check.php/continue/aHR0cHM6Ly9kZ3BvdC5jb20vcHJvZHVjdF9saXN0LnBocC9jUGF0aC8yNTQ/age_check/ok'
    #目的のページのurl
    url_target = 'https://dgpot.com/product_list.php/cPath/254'
    
    session = requests.session()
    session.get(yes_button_url)
    soup = BeautifulSoup(session.get(url_target).content, 'lxml')
    
    #タイトルを取得してprint
    elems = soup.select("[class='modern_item_list-title'] a")
    for elem in elems:
        print(elem.text)
    
[/code]

##### その3

この方法だと年齢認証ページがスクレイピングされてしまう

[code]

    import requests
    from bs4 import BeautifulSoup
    
    #クッションページの「はい」ボタンのurlからcookieを取得
    url = "https://dgpot.com/age_check.php/continue/aHR0cHM6Ly9kZ3BvdC5jb20vcHJvZHVjdF9saXN0LnBocC9jUGF0aC8yNTQ/age_check/ok"
    session = requests.session()
    response = session.get(url)
    # cookieを取得
    cookie = response.cookies
    # cookie内の任意項目を指定して取得
    item  = cookie.get('osCsid')
    
    #目的のページのurl
    url = 'https://dgpot.com/product_list.php/cPath/254'
    #ユーザーエージェントの設定
    headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"}
    #htmlの取得
    response = requests.get(url=url, headers=headers, cookies=cookie)
    html = response.content
    #BeautifulSoupで扱えるようにパース
    soup = BeautifulSoup(html, "html.parser")
    
    #タイトルを取得してprint
    elems = soup.select("[class='modern_item_list-title'] a")
    for elem in elems:
        print(elem.text)
    
[/code]


CC BY-SA 4.0
2021-10-11T11:46:33.743
83008
2021-10-24T13:14:27.563
2021-10-24T13:14:27.563
32986
48577
question
python python3 web-scraping beautifulsoup cookie
年齢認証があるサイトをPythonでスクレイピングしたい


> その2
>
> 年齢認証ページは通過でき、成人向け総合の２位までは取得できるが、それ以降がなぜか取得できない。

『クッションページの「はい」ボタンのurl』も変化する様なので、最初に「目的のページのurl」にアクセスして『「はい」ボタンのurl』を取得します。次にその
URL と目的のページの URL に再度アクセスしてスクレイピングを行います。

3位以降が取得できないのは、HTTP response のデコード(`bytes` -> `str`, `charset(encoding)` は
`EUC-JP`)に失敗している事が原因の様です。なので、デコードできない部分は切り捨てています(`'ignore'` を指定)。

[code]

    import requests
    from bs4 import BeautifulSoup
    
    #目的のページのurl
    url_target = 'https://dgpot.com/product_list.php/cPath/254'
    
    # first access
    session = requests.session()
    html = session.get(url_target).content
    soup = BeautifulSoup(html, 'lxml')
    #クッションページの「はい」ボタンのurl
    yes_button_url = [i.attrs.get('href') for i in soup.select('div.main_body.index_box a')][-1]
    
    # access again  
    session.get(yes_button_url)
    response = session.get(url_target)
    html = response.content.decode(response.encoding, 'ignore')
    soup = BeautifulSoup(html, 'lxml')
      
    #タイトルを取得してprint
    elems = soup.select('div.item_list_h:has(> a:-soup-contains("動画総合")) ~ ul li div.modern_item_list-title')
    for i, elem in enumerate(elems):
        print(i+1, elem.text)
    
[/code]


CC BY-SA 4.0
2021-10-11T20:41:42.180
83014
2021-10-11T20:41:42.180
47127
83008
answer