curl コマンドでも Pythonの requests でもそうなのですが、使用するときにUser Agentを指定することができます。
では、もし何も指定しなかったらどんな値が設定されているんだろうかと気になったのですが、意外に情報が出てこなかったものが多いのであれこれ調べてみました。ついでに他の手段についても調べています。
調査方法について
やり方としては、AWS Lambda の関数URLで、User Agentを表示するHTMLを作ってそこにアクセスします。
参考: Lambda の関数URLで送信されたデータを扱う
Pythonの場合、リクエスト元のUser Agentは、以下のコードで取れます。
event["requestContext"]["http"]["userAgent"]
Pandasのread_htmlも試したかったので、こんな感じの Lambda 関数を作ってTableで返すようにしてみました。
def lambda_handler(event, context):
html = """<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>{user_agent}
</table>""".format(user_agent=event["requestContext"]["http"]["userAgent"])
return {
"headers": {
"Content-Type": "text/html;charset=utf-8",
},
'statusCode': 200,
"body": html,
}
ブラウザでアクセスすると、以下の結果が得られます。
まぁ、普通にMac Book Proの Chrome ブラウザですね。なぜか Safari の文字列も入っています。
<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
</table>
ここから、色々試していきます。物によってはHTMLタグ部分省略してるのもありますが、LambdaはHTMLで結果返してきてます。
Curlコマンド編
まず、Curlコマンドです。 普通にさっきの lambda の 関数URLを叩きます。
$ curl https://{url-id}.lambda-url.{region}.on.aws/
<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>curl/7.79.1
</table>
# 参考 curl のバージョン情報
$ curl --version
curl 7.79.1 (x86_64-apple-darwin21.0) libcurl/7.79.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.45.1
Release-Date: 2021-09-22
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets
「curl/7.79.1」だけでしたね。超シンプルです。OSの情報とかゴテゴテついてくるかと思ってました。
この記事の本題からは外れますが、Curlは-A か -H オプションでUser Agentを指定できます。書き方が、違うので注意してください。-Aの方が簡単ですが、-Hの方が User Agent以外の設定とも統一的な書き方ができます。
$ curl https://{url-id}.lambda-url.{region}.on.aws/ -A "Chrome"
<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>Chrome
</table>
$ curl ≈ -H "User-Agent: Chrome"
<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>Chrome
</table>
設定できましたね。
ここからPythonのライブラリを見ていきます。
requests 編
ここからずっと同じURLを使うので、url って変数に入れておきます。
url = "https://{url-id}.lambda-url.{region}.on.aws/"
では、requestsでgetしてみましょう。
import requests
r = requests.get(url)
print(r.text)
"""
<!DOCTYPE html>
<table>
<tr><th>User Agent
<tr><td>python-requests/2.27.1
</table>
"""
これもまた随分シンプルなUser Agentでした。python-ってつくんですね。
2.27.1 は ライブラリのバージョンです。
$ pip freeze | grep requests
requests==2.27.1
別の値を設定したい場合は、headers 引数に curl の -H オプションのイメージで設定します。
headers = {'User-Agent': "Chrome"}
r = requests.get(url, headers=headers)
print(r.text)
"""
# 必要な行だけ抜粋
<tr><td>Chrome
"""
urllib 編
次はPython標準ライブラリのurllibです。
正直、requests に比べてはるかに使用頻度低いので軽く試すだけにします。
import urllib.request
urllib_response = urllib.request.urlopen(url)
urllib_html = urllib_response.read().decode("utf-8") # バイナリなのでデコードが必要
print(urllib_html)
"""
# 必要な行だけ抜粋
<tr><td>Python-urllib/3.9
"""
Python-urllib/3.9 と、これもまたかなりシンプルでした。特徴的なのは、 3.9 とPythonのバージョン番号がついてきましたね。さすが標準ライブラリです。
Pandasのread_html 編
最後に、PandasでHTMLからテーブルを抽出できるread_htmlメソッドについて実験します。これはかなり便利なメソッドなのでいずれ専用記事で紹介したいですね。HTMLのテキストだけでなくURLを渡すこともでき、そのURLにアクセスしてHTML中のテーブルをデータフレームの配列で返してくれます。データフレームの配列で返してくるので、以下のコードでは[0]で最初の要素を取り出しています。
import pandas as pd
df = pd.read_html(url)[0]
print(df)
"""
User Agent
0 Python-urllib/3.9
"""
結果はご覧の通り、Python-urllib/3.9 でした。先ほどの標準ライブラリの urllibが内部で動いているようです。Pandasっぽい値が設定されることなく、そのままurllibの情報が出てきました。
Pandasのドキュメントを見る限りでは、read_htmlで情報を取るときにUser Agentを指定する方法は用意されてないようです。
以上で、 curl / requests / urllib / pandas.read_html のデフォルトの User Agent がわかりました。分かったからといって特に使い道が思いついているわけではないですが、気になったことが調べられてよかったです。