記事のディレクトリ
ピットに年以上Acmerとして、いずれにせよ、他の人がこのようにしないことを知って、そして時には特に質問は、当然のことながら、OJの質問にナンバーワンの質問に行くことができますどのくらいのブラシ最後に知ってほしいが、これはプログラマではありませんしないでくださいどのように実践的なああ、そうそう機械的な仕事。今オープンソースプロジェクトがありますが、大きな問題ブラシOJの場合にカウントが、それでも自分の手で何かを達成したいことができます。つい最近、私はちょうど彼らの前に設定されたフラグアップを完了するために、Pythonの爬虫類を学びました。我々はCodeforces、HDU、POJ、羅バレーとタイトルの記録、統計およびACの数をクロールし、他の主流のOJブラシを達成し、最終的にQTとのインタフェースを実現します。いくつかの単語の男はcodeforcesがスタートで始まり、直接の質問に、言いました。
まず、ニーズ分析
- まず、URLの提出インタフェースを見つける必要があります。
- 分析依頼方法。
- ブラウザをチェックして、Webページのソースコード解析ツール。
- 私たちが必要なものを取得し、テキストまたはデータベースに保存。
- フリップ現在インタフェースを解析した後、次いで、上記の手順を繰り返します。
第二に、特定の実装
下には観光客例えば、ギャング情報インターフェイスを提出します。
- 分析のURLリンク
ちょうど提出インターフェイスを入力し始めた場合、URLはこれです
その後、我々はページをめくると、参照してください。次のようにURLのページには、インタフェースの法律で見つけることができ提出し、最終的に現在のページ番号。同期要求を使用します。それは同期要求があるので、それは、非常に簡単に処理することですHTMLテキストに直接アクセスして、行を解析します。
https://codeforces.com/submissions/username/page/2
- 送信要求
リクエストを送信することにより、ライブラリーの要求は、抗ないcodeforcesクローラいるので、ヘッダーを設定しないこともできます。
import requests
url = 'https://codeforces.com/submissions/tourist/page/1'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36'
}
response = requests.get(url=url, headers=headers)
- その後、分析ページ、パース
Chromeブラウザを使用して、チェックを選択し、提出したレコードを右クリックします。他のブラウザでは、似ています。
観察を見つけることができた後に、記録情報を記録TRタグをコミットの各テーブルに提出されています。私たちは、まずこれらのtrタグが抽出されるように持参して、私たちが望む情報(主題見出し、提出状況など)を解析することですので。
经过检查可以确定 data-submission-id这个属性是tr标签特有的,那么我们就可以通过这个属性来定位tr标签。使用pyquery进行解析(跟JQuery语法很类似,支持css selector)。
from pyquery import PyQuery as pq
doc=pq(response.text)
items = doc.find('[data-submission-id]').items() #将查到的元素生成一个迭代器方便便利。
把每个tr标签提取出来后,接下来开始对里面的td每个td标签下手了。我就提取了题目名字和提交状态。其他的方法一样。
现在对每个td单独进行解析。所以可以通过**.status-small>a定位到a标签。然后提取它的文本内容,也就是题目标题。但如果是从整个网页中中则不行,可以选择通过data-problemid这个特定标签来定位。使用:nth-child(6)**获取提交状态的内容。将获取的内容打包成一个字典。(当然其他形式也可以,然后看你要保存到数据库或者文本中了)
items = doc.find('[data-submission-id]').items()
for item in items:
it = solve_tr(item)
problemName = tr.find('.status-small>a').text()
state = tr.find(':nth-child(6)').text()
it = {'problemName': problemName, 'state': state}
problemName=tr.find('[data-problemid]>a').text()
- 获取页码数量
至此已经我们已经可以解析一页的提交内容了,但是如果实现翻页功能呢。要实现翻页功能其实很简单,只要将url最后的数字替换掉,就可以了。
https://codeforces.com/submissions/username/page/2
https://codeforces.com/submissions/username/page/3
重点在于我们应该翻页几次。对于翻页问题有两个解决方案,一个是死循环,一直进行下去,出现异常在停止,但是这个在codeforces这里是行不通的,因为如果超出页码后,会默认显示最后一页。所以我们就只能老老实实的统计页码数量了。
页码标签是在一个无序表中,倒数第二个li标签的内容存的就是总页码数,那么我们只要获取里面的内容就可以了。
通过nth-child选择器获取。
def get_pages_num(doc):
"""
获取需要爬取的页码数量
:param doc: pyquery返回的解析器
:return: int,页码数量
"""
try:
length = doc.find('#pageContent>.pagination>ul>*').length
last_li = doc.find('#pageContent>.pagination>ul>li:nth-child(' + str(length-1) + ')')
print('length', length)
print(last_li.text())
# for item in items:
# print(item)
return max(1, int(last_li.text()))
except Exception :
return None
现在爬取codeforces刷题记录的需求基本完成了,将上面的代码整理一下,就完工了。
三、完整代码
有个可以直接运行的代码是件非常愉快的事,所以我就把完整代码贴上来了
from pyquery import PyQuery as pq
import requests
import time
def solve_tr(tr):
"""
解析我们所需要的内容
:param tr: tr元素
:return: dict
"""
problemName = tr.find('.status-small>a').text()
state = tr.find(':nth-child(6)').text()
it = {'problemName': problemName, 'state': state}
return it
def get_pages_num(doc):
"""
获取需要爬取的页码数量
:param doc: pyquery返回的解析器
:return: int,页码数量
"""
try:
length = doc.find('#pageContent>.pagination>ul>*').length
last_li = doc.find('#pageContent>.pagination>ul>li:nth-child(' + str(length-1) + ')')
print('length', length)
print(last_li.text())
# for item in items:
# print(item)
return max(1, int(last_li.text()))
except Exception :
return None
def crawl_one_page(doc):
"""
爬取每一页中的内容
:param doc: pyquery返回的解析器
"""
items = doc.find('[data-submission-id]').items()
for item in items:
it = solve_tr(item)
with open('data.txt', 'a+', encoding='utf-8') as f:
f.write(str(it) + '\n')
print(it)
def get_username():
"""
获取用户名
:return:
"""
username = input('请输入用户名:')
return username
def main():
base = 'https://codeforces.com/submissions/'
username = get_username()
url = base+username+'/page/1'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36'
}
response = requests.get(url=url, headers=headers)
doc = pq(response.text)
# 注释部分为测试代码
# crawl_one_page(doc)
# with open('index.html', 'w', encoding='utf-8') as f:
# f.write(doc.text())
num = get_pages_num(doc)
if num is not None:
for i in range(1, num + 1):
url = base+username+'/page/'+str(i)
print(url)
response = requests.get(url=url)
doc = pq(response.text)
crawl_one_page(doc)
time.sleep(2)
else:
print('username is no exist or you are no submission')
if __name__ == '__main__':
main()
运行效果如下