Saya melihat masalah yang sama. Berikut adalah skrip kecil yang mencontohkan masalah.
import os
from datetime import datetime
from github import Github
# Login
TOKEN = os.getenv("GITHUB_ACCESS_TOKEN")
github = Github(TOKEN)
# Get initial rate limit and reset time
rl1 = github.get_rate_limit().rate
print("RL1 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl1.limit, rl1.remaining, rl1.reset))
# RL1 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.
# Perform a search
results = github.search_code("Hello World")
# Rate limit of Github instance is unchanged after a search
rl2 = github.get_rate_limit().rate
print("RL2 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl2.limit, rl2.remaining, rl2.reset))
# RL2 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.
# The PaginatedList instance has a Requestor with the same info
rl3 = results._PaginatedList__requester.rate_limiting
rl3_reset = datetime.utcfromtimestamp(int(
results._PaginatedList__requester.rate_limiting_resettime))
print("RL3 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl3[0], rl3[1], rl3_reset))
# RL3 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.
# However, the actual ContentFile results show a different limit
# The Requester of each individual result ...
result = results[0]
rl4 = result._requester.rate_limiting
rl4_reset = datetime.utcfromtimestamp(int(
result._requester.rate_limiting_resettime))
print("RL4 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl4[1], rl4[0], rl4_reset))
# RL4 | Limit: 30, Remaining: 29, Reset: 2017-09-22 16:27:36.
# ... and headers stored in the content file directly show a different rate limit.
rl5_limit = result._headers['x-ratelimit-limit']
rl5_remaining = result._headers['x-ratelimit-remaining']
rl5_reset = datetime.utcfromtimestamp(int(
result._headers['x-ratelimit-reset']))
print("RL5 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl5_limit, rl5_remaining, rl5_reset))
# RL5 | Limit: 30, Remaining: 29, Reset: 2017-09-22 16:27:36.
# In the end, the main Github instance still shows the original full rate limit
rl6 = github.get_rate_limit().rate
print("RL6 | Limit: {}, Remaining: {}, Reset: {}.".format(
rl6.limit, rl6.remaining, rl6.reset))
# RL6 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.
+1 Fitur ini diperlukan untuk aplikasi yang saya coba buat
@brentshermana untuk aplikasi Anda, pertimbangkan untuk memeriksa header batas tarif (dari respons terakhir; lihat contoh saya di atas) atau polling sendiri titik akhir /rate_limit
. Itu berisi informasi tentang semua jenis batas tarif dan tidak termasuk dalam batas tarif apa pun.
Akhirnya, akan lebih baik jika PyGithub tidak hanya mengurai rate
tetapi juga mengurai resources
dari apa yang dikembalikan /rate_limit
. Informasi yang ada, sayangnya tidak tersedia untuk konsumen perpustakaan.
Juga, daftar yang diberi halaman harus mengembalikan batas kecepatan untuk pencarian kode jika mengembalikan hasil pencarian seperti itu, yaitu apa pun yang disimpan di _headers['x-ratelimit-*']
.
btw: Saya baru saja memperhatikan, bidang rate
dari JSON yang dikembalikan oleh /rate_limit
tidak digunakan lagi dan informasi dalam resources
adalah alternatif yang disarankan: https://developer.github.com/ v3/rate_limit/#deprecation -pemberitahuan
Saya melakukan hal itu. Jika ada yang ingin mengadaptasi ini dan mencoba dan membuat permintaan tarik, Anda mendapat restu saya:
def wait(seconds):
print("Waiting for {} seconds ...".format(seconds))
time.sleep(seconds)
print("Done waiting - resume!")
def api_wait():
url = 'https://api.github.com/rate_limit'
response = urlopen(url).read()
data = json.loads(response.decode())
if data['resources']['core']['remaining'] <= 10: # extra margin of safety
reset_time = data['resources']['core']['reset']
wait(reset_time - time.time() + 10)
elif data['resources']['search']['remaining'] <= 2:
reset_time = data['resources']['search']['reset']
wait(reset_time - time.time() + 10)
Saya mengalami masalah di mana iterasi saya atas hasil dari search_issues berhenti setelah 1020 hasil ketika seharusnya ada 1869 hasil. Skrip saya berhenti di titik yang sama setiap saat. Mungkinkah ini masalah pembatasan tarif?
Saya tidak mendapatkan kesalahan, hasilnya habis begitu saja. Jika saya memasukkan string kueri saya langsung ke antarmuka web GitHub maka saya melihat semua hasil 1869, seperti yang diharapkan. 1020 adalah kelipatan dari 30, yang membuat saya bertanya-tanya apakah ini masalah pagination?
Kode adalah sebagai berikut:
querystring = "type:pr is:closed repo:xxxx closed:2017-07-01..2018-06-30"
issues = git.search_issues(query=querystring, sort="updated", order="asc")
for issue in issues:
pull = issue.as_pull_request()
print "%s: %s" % (pull.number, pull.title)
Terima kasih banyak atas tip yang dapat Anda bagikan tentang apa yang mungkin salah di sini.
Saya juga mencoba mengulangi issues.reversed
untuk melihat apakah itu akan dimulai pada akhir dari hasil 1869 yang saya harapkan. Namun dalam kasus ini saya hanya mendapatkan 30 masalah, dari halaman pertama hasil.
Pada penyelidikan lebih lanjut, tampaknya saya mengalami 1000 hasil per batas pencarian .
Bagaimana kalau kami menyediakan satu metode lagi get_search_rate_limit()
untuk batas tingkat pencarian sementara get_rate_limit()
yang ada akan mengurai batas tingkat "inti" terbaru yang disarankan oleh Github: https://developer.github.com/ v3/rate_limit/
Batas tingkat API Pencarian dan batas tingkat GraphQL tersedia sekarang. Satu metode untuk semua.
Secara default, ini akan menunjukkan kepada Anda batas kecepatan "inti". Anda juga bisa mendapatkan batas tingkat pencarian/graphql dengan mengakses atribut masing-masing.
r = g.get_rate_limit()
>>> r
RateLimit(core=Rate(remaining=4923, limit=5000))
>>> r.search
Rate(remaining=30, limit=30)
>>> r.graphql
Rate(remaining=5000, limit=5000)
Tampak hebat, terima kasih @sfdye!
Untuk meniru fungsi menunggu @brentshermana untuk menghindari masalah dengan pembatasan tingkat pencarian, Anda sekarang dapat melakukan sesuatu seperti ini:
from datetime import datetime
def api_wait_search(git):
limits = git.get_rate_limit()
if limits.search.remaining <= 2:
seconds = (limits.search.reset - datetime.now()).total_seconds()
print "Waiting for %d seconds ..." % (seconds)
time.sleep(seconds)
print "Done waiting - resume!"
Perhatikan bahwa menelepon get_rate_limit()
akan menyebabkan penundaan kecil, jadi Anda mungkin ingin meminimalkan seberapa sering Anda menelepon ini.
Untuk orang yang mendarat di sini dari mesin pencari, saya sedikit memodifikasi fungsi @bbi-yggy:
from datetime import datetime, timezone
def rate_limited_retry(github):
def decorator(func):
def ret(*args, **kwargs):
for _ in range(3):
try:
return func(*args, **kwargs)
except RateLimitExceededException:
limits = github.get_rate_limit()
reset = limits.search.reset.replace(tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
seconds = (reset - now).total_seconds()
print(f"Rate limit exceeded")
print(f"Reset is in {seconds:.3g} seconds.")
if seconds > 0.0:
print(f"Waiting for {seconds:.3g} seconds...")
time.sleep(seconds)
print("Done waiting - resume!")
raise Exception("Failed too many times")
return ret
return decorator
Fungsi ini dapat digunakan sebagai berikut:
@rate_limited_retry(github)
def run_query(import_string):
query_string = f"language:Python \"{import_string}\""
return list(github.search_code(query_string))
results = run_query(import_string)
Versi modifikasi dari pokey's decorator di atas dengan mempertimbangkan core/search/graphql.
Juga menambahkan penundaan 30 detik karena Github tidak mengatur ulang batas kecepatan tepat pada waktu yang disebutkan.
def rate_limited_retry():
def decorator(func):
def ret(*args, **kwargs):
for _ in range(3):
try:
return func(*args, **kwargs)
except RateLimitExceededException:
limits = gh.get_rate_limit()
print(f"Rate limit exceeded")
print("Search:", limits.search, "Core:", limits.core, "GraphQl:", limits.graphql)
if limits.search.remaining == 0:
limited = limits.search
elif limits.graphql.remaining == 0:
limited = limits.graphql
else:
limited = limits.core
reset = limited.reset.replace(tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
seconds = (reset - now).total_seconds() + 30
print(f"Reset is in {seconds} seconds.")
if seconds > 0.0:
print(f"Waiting for {seconds} seconds...")
time.sleep(seconds)
print("Done waiting - resume!")
raise Exception("Failed too many times")
return ret
return decorator
Komentar yang paling membantu
Untuk orang yang mendarat di sini dari mesin pencari, saya sedikit memodifikasi fungsi @bbi-yggy:
Fungsi ini dapat digunakan sebagai berikut: