web-dev-qa-db-ja.com

Pythonの要求はCloudFlareのセキュリティをトリガーしますが、URLLIBがそうでない

私はレストランのウェブサイトの自動WebScrapperに取り組んでいますが、問題があります。このウェブサイトはCloudLFAREの対戦禁止セキュリティを使用しています。これは、アンダーアタックモードではなく、非米国のIPやボットを検出したときにのみトリガーするCAPTCHAテストをバイパスします。 CloodFlareのセキュリティがトリガー、JavaScriptを無効にするとき、またはアメリカのプロキシを使用しているときにそれを迂回しようとしています。

これを知って、私はそのようなPythonの要求ライブラリを使用してみました:

import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0'}
response = requests.get("https://grimaldis.myguestaccount.com/guest/accountlogin", headers=headers).text
print(response)
 _

しかし、これは私が使用するプロキシに関係なく、CloudFlareをトリガーすることになります。

[〜#〜]。しかし、[〜#〜] urllib.Requestを使用すると、次のようになります。

import urllib.request
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0'}
request = urllib.request.Request("https://grimaldis.myguestaccount.com/guest/accountlogin", headers=headers)
r = urllib.request.urlopen(request).read()
print(r.decode('utf-8'))
 _

同じアメリカのIPを持つRANが実行されると、リクエストライブラリと同じヘッダーとIPを使用しても、CloudFlareのセキュリティはトリガーされません。

それで、URLLIBライブラリに含まれていない要求ライブラリにCloudFlareを正確に起動しているものを理解しようとしています。

典型的な答えは「ただurllibを使う」でしょう。私は他のhttplib(特に非同期のもの)に検索できる修正を適用することができます

編集N°2:これまでのところへの進歩:

@tuangeekのおかげで、ドメイン名ではなくホストIPに直接接続する限り、CloudFlareブロックを要求を使用してバイパスすることができます(何らかの理由で、RequestsによるDNSリダイレクトはCloudFlareをトリガーしますが、URLLIBはそうではありません)。

import requests
from collections import OrderedDict
import socket

# grab the address using socket.getaddrinfo
answers = socket.getaddrinfo('grimaldis.myguestaccount.com', 443)
(family, type, proto, canonname, (address, port)) = answers[0]
headers = OrderedDict({
    'Host': "grimaldis.myguestaccount.com",
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0',
})
s = requests.Session()
s.headers = headers
response = s.get(f"https://{address}/guest/accountlogin", verify=False).text
 _

注意:HTTP経由でアクセスしようとすると(Verify Varableがfalseに設定されている場合はhttpsではなく)CloudFlareのブロックがトリガーされます。

今これは素晴らしいですが、残念ながら、この作業をhttplib httpxと非同期的にするという私の最後の目標は、次のコードを使用しているので、CloudFlareブロックはまだホストIPを介して直接接続されていてもトリガーされます。適切なヘッダー、およびVerifyがFalseに設定されているもの:

import trio
import httpx
import socket
from collections import OrderedDict
answers = socket.getaddrinfo('grimaldis.myguestaccount.com', 443)
(family, type, proto, canonname, (address, port)) = answers[0]
headers = OrderedDict({
    'Host': "grimaldis.myguestaccount.com",
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0',
})
async def asks_worker():
    async with httpx.AsyncClient(headers=headers, verify=False) as s:
        r = await s.get(f'https://{address}/guest/accountlogin')
        print(r.text)
async def run_task():
    async with trio.open_nursery() as nursery:
        nursery.start_soon(asks_worker)
trio.run(run_task)
 _

編集N°1:詳細については、ここではURLLIBからの生のHTTP要求と要求

リクエスト:

send: b'GET /guest/nologin/account-balance HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: grimaldis.myguestaccount.com\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0\r\nConnection: close\r\n\r\n'
reply: 'HTTP/1.1 403 Forbidden\r\n'
header: Date: Thu, 02 Jul 2020 20:20:06 GMT
header: Content-Type: text/html; charset=UTF-8
header: Transfer-Encoding: chunked
header: Connection: close
header: CF-Chl-Bypass: 1
header: Set-Cookie: __cfduid=df8902e0b19c21b364f3bf33e0b1ce1981593721256; expires=Sat, 01-Aug-20 20:20:06 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
header: Expires: Thu, 01 Jan 1970 00:00:01 GMT
header: X-Frame-Options: SAMEORIGIN
header: cf-request-id: 03b2c8d09300000ca181928200000001
header: Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
header: Set-Cookie: __cfduid=df8962e1b27c25b364f3bf66e8b1ce1981593723206; expires=Sat, 01-Aug-20 20:20:06 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Vary: Accept-Encoding
header: Server: cloudflare
header: CF-RAY: 5acb25c75c981ca1-EWR
 _

ウルリブ:

send: b'GET /guest/nologin/account-balance HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: grimaldis.myguestaccount.com\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0\r\nConnection: close\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Date: Thu, 02 Jul 2020 20:20:01 GMT
header: Content-Type: text/html;charset=utf-8
header: Transfer-Encoding: chunked
header: Connection: close
header: Set-Cookie: __cfduid=db9de9687b6c22e6c12b33250a0ded3251292457801; expires=Sat, 01-Aug-20 20:20:01 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Expires: Thu, 2 Jul 2020 20:20:01 GMT
header: Cache-Control: no-cache, private, no-store
header: X-Powered-By: Undertow/1
header: Pragma: no-cache
header: X-Frame-Options: SAMEORIGIN
header: Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.google-analytics.com/analytics.js https://use.typekit.net connect.facebook.net/ https://googleads.g.doubleclick.net/ app.pendo.io cdn.pendo.io pendo-static-6351154740266000.storage.googleapis.com pendo-io-static.storage.googleapis.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.google.com/recaptcha/api.js apis.google.com https://www.googletagmanager.com api.instagram.com https://app-rsrc.getbee.io/plugin/BeePlugin.js https://loader.getbee.io api.instagram.com https://bat.bing.com/bat.js https://www.googleadservices.com/pagead/conversion.js https://connect.facebook.net/en_US/fbevents.js  https://connect.facebook.net/ https://fonts.googleapis.com/ https://ssl.gstatic.com/ https://tagmanager.google.com/;style-src 'unsafe-inline' *;img-src * data:;connect-src 'self' app.pendo.io api.feedback.us.pendo.io; frame-ancestors 'self' app.pendo.io pxsweb.com *.pxsweb.com;frame-src 'self' *.myguestaccount.com https://app.getbee.io/ *;
header: X-Lift-Version: Unknown Lift Version
header: CF-Cache-Status: DYNAMIC
header: cf-request-id: 01b2c5b1fa00002654a25485710000001
header: Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
header: Set-Cookie: __cfduid=db9de811004e591f9a12b66980a5dde331592650101; expires=Sat, 01-Aug-20 20:20:01 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Set-Cookie: __cfduid=db9de811004e591f9a12b66980a5dde331592650101; expires=Sat, 01-Aug-20 20:20:01 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Set-Cookie: __cfduid=db9de811004e591f9a12b66980a5dde331592650101; expires=Sat, 01-Aug-20 20:20:01 GMT; path=/; domain=.myguestaccount.com; HttpOnly; SameSite=Lax; Secure
header: Server: cloudflare
header: CF-RAY: 5acb58a62c5b5144-EWR
 _
10
Tom

いくつかのデバッグの後、@Tuangeekの答えのおかげで、私たちはCloudFlareを扱うときに要求の要求のDNS問題から来るように思われるという問題を見つけました、この問題に対する簡単な修正は直接接続していますそのようなホストIP

import requests
from collections import OrderedDict
from requests import Session
import socket

# grab the address using socket.getaddrinfo
answers = socket.getaddrinfo('grimaldis.myguestaccount.com', 443)
(family, type, proto, canonname, (address, port)) = answers[0]

s = Session()
headers = OrderedDict({
    'Accept-Encoding': 'gzip, deflate, br',
    'Host': "grimaldis.myguestaccount.com",
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0'
})
s.headers = headers
response = s.get(f"https://{address}/guest/accountlogin", headers=headers, verify=False).text
print(response)
 _

今、この修正はHTTPLIB httpxを操作するときには機能しませんでしたが、問題が発見された場所を見つけました。

この問題はH11ライブラリ(HTTPXがHTTP/1.1要求を処理するために使用されています)から来ていますが、URLLIBはヘッダーの文字ケースを自動的に修正します.H11はヘッダーごとに倒れることで異なるアプローチを取りました。理論的には、サーバーが大文字と小文字を区別しない方法でヘッダーを処理する必要があるため、これは問題を引き起こすべきではありません(そして、それらが行う場合)、現実はHTTPがHard™Ⅲ、CloudFlareなどのサービスが尊重されないことです。 RFC2616で、ヘッダーを適切に大文字にする必要があります。

大文字の議論は、H11でしばらく経過しています。

https://github.com/python-hyper/h11/issues/31

そして、「最近」httpxのレポにもポップアップし始めました:

https://github.com/encode/httpx/issues/538

https://github.com/encode/httpx/issues/728

CloudFlareとHTTPXの問題に対する不満足な回答は、H11の側面で何かが終わるまで(またはCloudFlareが奇跡的にRFC2616を尊重するまで)、HTTXとCloudFlareのヘッダーの大文字にかかるように変更することはできません。

AIOHTTPや要求先物などの異なるHTTPLIBを使用してください.H11でヘッダーの資本化を自分で予測してパッチしてみてください。また、H11チームによって適切に対処するための問題を待ってください。

3
Tom