Python爬虫入门例题:抓取牛客网题目

最近做题的时候要写一些题解,在把牛客网的题目复制下来的时候,数学公式的处理比较麻烦,所以我用Python的selenium、urllib.request和BeautifulSoup4库对题目信息进行了爬取,写题解的时候时间节约了很多。

2. 前期准备

安装selenium、urllib和BeautifulSoup库。

pip3 install urllib

pip3 install selenium

pip3 install beautifulsoup4

3. 获取网页内容

以 牛客网 NC204552 咪咪游戏 为例。

# 导入库

import urllib.request

import bs4

import time

from bs4 import BeautifulSoup

from selenium import webdriver

# 题目属性

problemId = "204552"

# 打开浏览器,模拟登陆

# 此处用的是Chrome,如果没有安装可以替换为其他支持的浏览器

driver = webdriver.Chrome()

获取网页内容

# 获取页面内容

# 题目链接

url = f"https://ac.nowcoder.com/acm/problem/{problemId}"

# 打开网页

driver.get(url)

# 网页加载等待时间

time.sleep(3)

# 找到 输入 用户名 和密码框,并且设置内容

username = driver.find_element_by_id('jsEmailIpt')

# 输入账号名,xxx替换为自己的账户名

username.send_keys('xxx')

time.sleep(1)

password = driver.find_element_by_id('jsPasswordIpt')

#输入密码,xxx替换为自己的密码

password.send_keys('xxx')

time.sleep(1)

# 分析网页,找到登录按钮

login = driver.find_elements_by_css_selector('div[class=col-input-login] a')[0]

# 点击按钮

login.click()

time.sleep(3)

# 格式化源代码

soup = BeautifulSoup(driver.page_source,'lxml')

# 退出浏览器

driver.quit()

存储和预处理

# 存储

data_dict = {}

# 找到主体内容

mainContent = soup.find_all(name="div", attrs={"class" :"terminal-topic"})[0]

# 去除公式的重复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. 内容处理

4.1. Limit

先从比较简单的信息入手,找到题目标题、时间、和内存限制。

# Limit

# 找到题目标题、时间、和内存限制

div = mainContent.find_all(name="div", attrs={"class":"subject-item-wrap"})[0].find_all("span")

# 放入字典中存储

data_dict['Title'] = f"牛客网 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]

定义函数,处理主体内容中诡异的空格和公式的符号。

def divTextProcess(div):

    """

    处理<div>标签中的文本内容

    """

#    获取文本

    strBuffer = div.get_text()

#    替换公式标记

    strBuffer = strBuffer.replace("{", " $").replace("}", "$ ")

#    去除多个空格

    strBuffer = strBuffer.replace("  ", "")

#    去除多个换行符

    strBuffer = strBuffer.replace("\n\n\n", "\n")

#    去除内容中用\xa0表示的空格

    strBuffer = strBuffer.replace("\xa0", "")

#    去除首位空格

    strBuffer = strBuffer.strip()

    # 返回结果

    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

输入样例,用代码框环境包围。

# 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')

下面是最后的输出结果

### Title

牛客网 NC204552 咪咪游戏

### Time Limit

C/C++ 1秒,其他语言2秒

### Memory Limit

C/C++ 524288K,其他语言1048576K

### Problem Description

牛牛最近喜欢玩咪咪游戏,于是自己写了个程序编了个游戏让牛妹来玩。游戏是这样的:

牛牛有一个长的字符串(只包26含个小写字母),他想让牛妹判断这个字符串是好的。

定义一个串是好的:这个串是由连续的mq连接而成的。

比如 $mqmq$ 说明这个串是好的, $mqmqm$ 或 $mqmqx$ 都是不好的。现在牛牛 想问牛妹这个串是否是好的,如果好的输出 $Yes$ ,否则输出 $No$

### Input

第一行一个整数Q,表示询问次数

就下来Q行,一个字符串$s

### Output

Q行,每行输出 $Yes$ 或 $No$

### Sample Input

// 这里会有```cpp代码环境,在这里为了展示方便去掉了

4

mqmq

mqmqm

mqakioi

mqqmmq

### Sample Onput

Yes

No

No

No

### Note

对于 $60\%$ 的数据满足: $|s|<=10,Q<=10$ 且保证只出现m,q两个字符

对于 $100\%$ 的数据: $|s| <=10^5,Q<=10$

对于所有数据保证只出现26个英文小写字母

### Source

[牛客网 NC204552 咪咪游戏](https://ac.nowcoder.com/acm/problem/204552)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352