最近做題的時(shí)候要寫(xiě)一些題解炉媒,在把牛客網(wǎng)的題目復(fù)制下來(lái)的時(shí)候昆烁,數(shù)學(xué)公式的處理比較麻煩吊骤,所以我用Python的selenium、urllib.request和BeautifulSoup4庫(kù)對(duì)題目信息進(jìn)行了爬取静尼,寫(xiě)題解的時(shí)候時(shí)間節(jié)約了很多白粉。
2. 前期準(zhǔn)備
安裝selenium、urllib和BeautifulSoup庫(kù)鼠渺。
pip3 install urllib
pip3 install selenium
pip3 install beautifulsoup4
3. 獲取網(wǎng)頁(yè)內(nèi)容
以?叛及停客網(wǎng) NC204552 咪咪游戲?為例。
# 導(dǎo)入庫(kù)
import urllib.request
import bs4
import time
from bs4 import BeautifulSoup
from selenium import webdriver
# 題目屬性
problemId = "204552"
# 打開(kāi)瀏覽器拦盹,模擬登陸
# 此處用的是Chrome鹃祖,如果沒(méi)有安裝可以替換為其他支持的瀏覽器
driver = webdriver.Chrome()
獲取網(wǎng)頁(yè)內(nèi)容
# 獲取頁(yè)面內(nèi)容
# 題目鏈接
url = f"https://ac.nowcoder.com/acm/problem/{problemId}"
# 打開(kāi)網(wǎng)頁(yè)
driver.get(url)
# 網(wǎng)頁(yè)加載等待時(shí)間
time.sleep(3)
# 找到 輸入 用戶(hù)名 和密碼框,并且設(shè)置內(nèi)容
username = driver.find_element_by_id('jsEmailIpt')
# 輸入賬號(hào)名普舆,xxx替換為自己的賬戶(hù)名
username.send_keys('xxx')
time.sleep(1)
password = driver.find_element_by_id('jsPasswordIpt')
#輸入密碼恬口,xxx替換為自己的密碼
password.send_keys('xxx')
time.sleep(1)
# 分析網(wǎng)頁(yè)校读,找到登錄按鈕
login = driver.find_elements_by_css_selector('div[class=col-input-login] a')[0]
# 點(diǎn)擊按鈕
login.click()
time.sleep(3)
# 格式化源代碼
soup = BeautifulSoup(driver.page_source,'lxml')
# 退出瀏覽器
driver.quit()
存儲(chǔ)和預(yù)處理
# 存儲(chǔ)
data_dict = {}
# 找到主體內(nèi)容
mainContent = soup.find_all(name="div", attrs={"class" :"terminal-topic"})[0]
# 去除公式的重復(fù)html元素
for each in mainContent.find_all('mrow'):
? ? each.decompose()
for each in mainContent.find_all(name="span", attrs={"class" :"katex-html"}):
? ? each.decompose()
# 更換換行符
for each in mainContent.find_all('br'):
? ? each.replace_with("\n\n")
4. 內(nèi)容處理
4.1. Limit
先從比較簡(jiǎn)單的信息入手,找到題目標(biāo)題祖能、時(shí)間地熄、和內(nèi)存限制。
# Limit
# 找到題目標(biāo)題芯杀、時(shí)間、和內(nèi)存限制
div = mainContent.find_all(name="div", attrs={"class":"subject-item-wrap"})[0].find_all("span")
# 放入字典中存儲(chǔ)
data_dict['Title'] = f"叛盘叮客網(wǎng) NC{problemId} " + soup.title.contents[0]
# Time Limit
data_dict['Time Limit'] = div[0].contents[0].split(':')[1]
# Memory Limit
data_dict['Memory Limit'] = div[1].contents[0].split(':')[1]
定義函數(shù)揭厚,處理主體內(nèi)容中詭異的空格和公式的符號(hào)。
def divTextProcess(div):
? ? """
? ? 處理<div>標(biāo)簽中的文本內(nèi)容
? ? """
#? ? 獲取文本
? ? strBuffer = div.get_text()
#? ? 替換公式標(biāo)記
? ? strBuffer = strBuffer.replace("{", " $").replace("}", "$ ")
#? ? 去除多個(gè)空格
? ? strBuffer = strBuffer.replace("? ", "")
#? ? 去除多個(gè)換行符
? ? strBuffer = strBuffer.replace("\n\n\n", "\n")
#? ? 去除內(nèi)容中用\xa0表示的空格
? ? strBuffer = strBuffer.replace("\xa0", "")
#? ? 去除首位空格
? ? strBuffer = strBuffer.strip()
? ? # 返回結(jié)果
? ? return strBuffer
4.2. Problem Description
獲取題目描述
# 處理題目描述
div = mainContent.find_all(name="div", attrs={"class": "subject-question"})[0]
data_dict['Problem Description'] = divTextProcess(div)
4.3. Input
輸入描述
div = mainContent.find_all(name="pre")[0]
data_dict['Input'] = divTextProcess(div)
4.4. Output
輸出描述
div = mainContent.find_all(name="pre")[1]
data_dict['Output'] = divTextProcess(div)
4.5. Sample Input & Onput
輸入樣例扶供,用代碼框環(huán)境包圍筛圆。
# Input
div = mainContent.find_all(name="div", attrs={"class":"question-oi-cont"})[0]
data_dict['Sample Input'] = "```cpp" + div.get_text() + '```'
# Onput
div = mainContent.find_all(name="div", attrs={"class":"question-oi-cont"})[1]
data_dict['Sample Onput'] = "```cpp" + div.get_text() + '```'
4.6. Note
備注
# 若有備注
if len(mainContent.find_all(name="pre")) >= 5:
? ? div = mainContent.find_all(name="pre")[-1]
? ? data_dict['Note'] = divTextProcess(div)
4.7. Source
題目鏈接
data_dict['Source'] = '[' + data_dict['Title'] + ']' + '(' + url + ')'
5. 輸出
for each in data_dict.keys():
? ? print('### ' + each + '\n')
? ? print(data_dict[each].replace("\n\n**", "**").replace("**\n\n", "**") + '\n')
下面是最后的輸出結(jié)果
### Title
牛客網(wǎng) NC204552 咪咪游戲
### Time Limit
C/C++ 1秒椿浓,其他語(yǔ)言2秒
### Memory Limit
C/C++ 524288K太援,其他語(yǔ)言1048576K
### Problem Description
牛牛最近喜歡玩咪咪游戲,于是自己寫(xiě)了個(gè)程序編了個(gè)游戲讓牛妹來(lái)玩扳碍。游戲是這樣的:
牛牛有一個(gè)長(zhǎng)的字符串(只包26含個(gè)小寫(xiě)字母)提岔,他想讓牛妹判斷這個(gè)字符串是好的。
定義一個(gè)串是好的:這個(gè)串是由連續(xù)的mq連接而成的笋敞。
比如 $mqmq$ 說(shuō)明這個(gè)串是好的碱蒙, $mqmqm$ 或 $mqmqx$ 都是不好的。現(xiàn)在牛牛 想問(wèn)牛妹這個(gè)串是否是好的夯巷,如果好的輸出 $Yes$ 赛惩,否則輸出 $No$
### Input
第一行一個(gè)整數(shù)Q,表示詢(xún)問(wèn)次數(shù)
就下來(lái)Q行趁餐,一個(gè)字符串$s
### Output
Q行喷兼,每行輸出 $Yes$ 或 $No$
### Sample Input
// 這里會(huì)有```cpp代碼環(huán)境,在這里為了展示方便去掉了
4
mqmq
mqmqm
mqakioi
mqqmmq
### Sample Onput
Yes
No
No
No
### Note
對(duì)于 $60\%$ 的數(shù)據(jù)滿(mǎn)足: $|s|<=10,Q<=10$ 且保證只出現(xiàn)m,q兩個(gè)字符
對(duì)于 $100\%$ 的數(shù)據(jù): $|s| <=10^5,Q<=10$
對(duì)于所有數(shù)據(jù)保證只出現(xiàn)26個(gè)英文小寫(xiě)字母
### Source
[藕罄祝客網(wǎng) NC204552 咪咪游戲](https://ac.nowcoder.com/acm/problem/204552)