每天的问题数量应与51区相同。显然,直接刮取Area 51会容易得多,但是我想自己弄清楚以进行练习。
我不是Python或Web API的专家,所以我希望您能用好代码评论人员可以帮助我改善实践。
import requests, datetime, time
def seconds_since_epoch(dt):
epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
return int((dt - epoch).total_seconds())
today = datetime.datetime.now(datetime.timezone.utc)
params = {
"site": "codegolf",
"fromdate": seconds_since_epoch(today - datetime.timedelta(days=14)),
"todate": seconds_since_epoch(today),
"pagesize": 100,
"page": 1
}
base_url = "https://api.stackexchange.com/2.2"
results = []
while True:
req = requests.get(base_url + "/questions", params=params)
contents = req.json()
results.extend(contents["items"])
if not contents["has_more"]:
break
if "backoff" in contents:
time.sleep(contents["backoff"])
params["page"] += 1
questions_per_day = len(results) / 14
answers_per_question = sum([q["answer_count"] for q in results]) / len(results)
print("Over the past 2 weeks, PPCG has had...")
print(round(questions_per_day, 1), "questions per day")
print(round(answers_per_question, 1), "answers per question")
我的方法是使用
dict
构建查询,并使用requests
模块向API发出请求。我将页面大小设置为最大,以减少发出的请求数,以免每日配额用尽那么快。代码托管在GitHub上,如果您想分叉和适应出于自己的目的,假设它不太可怕。
#1 楼
您的seconds_since_epoch
函数具有内置的Python等效项datetime.timestamp
。如果使用
from datetime import datetime, timezone
,您的命名空间会更干净。 。 base_url
更好地命名为urllib.parse.urljoin
。在
results
中,questions
多余且效率低。/>
不是连续3次q4312079而是创建多行格式的字符串并打印一次。
您永远不会创建返回问题的函数,也不会定义主函数。我建议在主函数中打印,该函数调用一个获取并返回问题信息的函数。
这是我的编程方式:
import requests
import time
from datetime import datetime, timezone, timedelta
def get_question_info(site, start, stop):
API_URL = "https://api.stackexchange.com/2.2/questions"
req_params = {
"site": site,
"fromdate": int(start.timestamp()),
"todate": int(stop.timestamp()),
"pagesize": 100,
"page": 1
}
questions = []
while True:
req = requests.get(API_URL, params=req_params)
contents = req.json()
questions.extend(contents["items"])
if not contents["has_more"]:
break
req_params["page"] += 1
if "backoff" in contents:
time.sleep(contents["backoff"])
return questions
def get_area51_estimate(site):
now = datetime.now(timezone.utc)
fortnight_ago = now - timedelta(days=14)
questions = get_question_info(site, fortnight_ago, now)
avg_questions = len(questions) / 14
avg_answers = sum(q["answer_count"] for q in questions) / len(questions)
return avg_questions, avg_answers
if __name__ == "__main__":
msg = """Over the past 2 weeks, PPCG has had...
{:.1f} questions per day
{:.1f} answers per question"""
print(msg.format(*get_area51_estimate("codegolf")))
评论
\ $ \ begingroup \ $
在您的第三点上,您说的是OP当前未使用该urljoin方法,但是它们应该/应该是吧?我认为您在该句子中缺少一些单词。
\ $ \ endgroup \ $
– SirPython
16年2月18日在23:15
\ $ \ begingroup \ $
您是否将API_URL固定在大写形式,因为它是恒定的?
\ $ \ endgroup \ $
– Alex A.
16-2-18在23:51
\ $ \ begingroup \ $
@AlexA。正确。
\ $ \ endgroup \ $
–orlp
16-2-18在23:58
#2 楼
代码样式import requests, datetime, time
根据PEP8,导入不应排成一行
您的代码不符合不能满足PEP8的“一行上字符太多”规则,但是,应避免在一行上出现这样的内容:
epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
base_url
:不要将
base_url
用于添加/questions
的其他任何东西,因此只需将其原样添加到base_url
中即可。 (然后将其重命名为url
)base_url + "/questions"
14是什么?以及为什么要将其除以结果量?
应将幻数移至另一个变量以提高可读性。
len(results) / 14
删除
"site": "codegolf"
我在聊天中向您提到了此内容,但是如果您对站点名称进行快速
input()
的操作,则可以将该脚本扩展到任何API支持的站点。class
结构:基于以上观点,如果使用
class
结构,则可以提取大多数将此逻辑分解为不同的部分,并使用生成器来获取下一页,而不是增加页面参数。评论
\ $ \ begingroup \ $
如果每个导入都应放在单独的行上,那么使用Python语法中的逗号有什么意义? :/
\ $ \ endgroup \ $
– Conor O'Brien
16-2-18在23:42
\ $ \ begingroup \ $
我认为这是PEP8之前的核心语言功能
\ $ \ endgroup \ $
– Quill
16-2-18在23:43
\ $ \ begingroup \ $
当从特定模块导入模块/方法/等时,通常使用逗号。 “不使用逗号”规则仅在仅导入根模块时适用。可以将其概括为“每个模块都有自己的导入行”。
\ $ \ endgroup \ $
–凯文·布朗
16-2-19的2:32
\ $ \ begingroup \ $
@KevinBrown很有意思,谢谢您的解释:-)
\ $ \ endgroup \ $
– Quill
16-2-19的2:33
\ $ \ begingroup \ $
我创建了一些使用类和生成器的东西,这可能很有用-请参见此处。用法非常简单。
\ $ \ endgroup \ $
–马特·迪卡利翁(Matt Deacalion)
16年2月24日在9:23
#3 楼
有点含糊不清params = {
...
}
...
while True:
req = requests.get(base_url + "/questions", params=params)
为什么不为
params
变量命名呢?最后一行比您将变量命名为site_info
之类的名称更难读,因为不熟悉Python的怪异之处的人可能更容易将命名参数与变量区分开。 (作为经常使用JavaScript的程序员,这句话肯定使我感到困惑。\ _(ツ)_ /¯。)此外,它更具可读性,因为您的脑子不必采取额外的步骤来区分命名变量。参数。评论
\ $ \ begingroup \ $
@SirPython我不知道,我很喜欢ES6。但是正如Quill所说的,显然……我仍然不了解它。
\ $ \ endgroup \ $
– Conor O'Brien
16-2-18在23:19
\ $ \ begingroup \ $
@CᴏɴᴏʀO'Bʀɪᴇɴ我很抱歉;我将其误认为是另一项功能(您可以在其中指定参数的默认值。
\ $ \ endgroup \ $
– SirPython
16-2-18在23:20
\ $ \ begingroup \ $
@SirPython啊,我知道了。这是有道理的,也是导致我自己对命名参数感到困惑的原因。 ;)
\ $ \ endgroup \ $
– Conor O'Brien
16-2-18在23:21
评论
嗨Alex:D为Python新手提供了不错的代码;)@cat谢谢!我对Python足够熟悉,足以发挥作用,但是我一直没有足够地使用它来擅长于此。 :P