查看结果
源码在最下面,但如果真正想要学习python爬虫或者想要了解我的思路的人,我希望可以耐心看完我的详细解读,不然这些代码永远不属于你
正在进行的比赛
即将开始的比赛
制作过程
爬取思路
首先我们访问ctftime
圈出的地方就是正在进行的ctf的比赛和即将进行的ctf比赛的信息
查看可以看到这个主页并没有给出相关比赛网址,只有比赛名称和比赛时间
访问一个网站看看
发现详细网页中有所有我们想要的信息,我们可以通过爬取每一个详细网站来获取信息。
最后找到了规律,每一个详细网站都是由下面的方式组成的
https://ctftime.org/event/XXXX
而xxxx则可以在首页中查看到
那么我的思路就清晰了,先在首页爬取到相应的四位数字,然后拼凑成新的url,并对新的url进行爬取,从而获得信息。
正在进行的比赛
我发现当我选中
<table width="100%">
时,我们的目标信息就都会被选中,那么我们就从这里下手
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
ctf_today = bs_url.find_all('table', width='100%')
可以看到我们初步获取了四位数字信息,但是还需要我们进一步缩小定位
可以看到四位数字信息在td>a标签下,我们进行进一步读取
for today1 in ctf_today:
today_td = today1.find_all('td')
for today2 in today_td:
today_a = today2.find('a')
if today_a:
print(today_a)
已经提取到最小标签,然后我们过滤掉多余的内容,由于都是重复的赘余,所以我们可以直接用替换的方式过滤
today_a_str = str(today_a)
today_url = re.sub('<a href="/event/|" style="color: #000000">|<img alt="Jeopardy" border="0" rel="tooltip" src="/static/images/ct/1.png" title="Jeopardy"/></a>|\n', '', today_a_str)
即将进行的比赛
当我们选中
<table class="table table-striped upcoming-events">
时,我们的目标信息就都会被选中
url_event = "https://ctftime.org/event/"
# ctf = {} # 写入字典用
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
ctf_come = bs_url.find_all('table', class_='table table-striped upcoming-events')
四位数字信息在a标签下,我们进行进一步读取
for come1 in ctf_come:
come_tr = come1.find_all('a')
for come2 in come_tr:
print(come2)
过滤掉多余的内容,由于这里并不统一,我采用了读取前20位,然后在过滤掉开头的相同部分
for come1 in ctf_come:
come_tr = come1.find_all('a')
for come2 in come_tr:
come3 = str(come2)
come4 = come3[0:20]
come_url = re.sub('<a href="/event/', '', come4)
爬取详细网站
首先拼接url
url_event = "https://ctftime.org/event/"
new_url = url_event + today_url
然后分析比赛详细网站
比赛名称
比赛名称没什么难度,就是简答的读取过滤
def get_name(url): # 获取比赛名称
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
name = bs_url.find_all('h2')
final_name = re.sub('<h2>|<i class="icon-play-circle" id="progress" rel="tooltip"></i></h2>|</h2>', '',str(name)) # 比赛名称
return final_name
except:
print("比赛名称获取失败")
比赛时间
这里有一个难点就是获取的信息不统一,无法直接过滤,但是这个不同点就是那四位数字,所以我们可以同时在函数中导入四位数字
def get_time(url,num): # 获取比赛时间
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
times = bs_url.find('div', class_='span10')
time = times.find('p')
time_str = str(time)
final_time = re.sub('<p>|<a href="/event/|.ics|" id="calendar" rel="tooltip">|<img class="svg_icon" id="icon_calendar" src="/static/img/icon_cal.svg"/>|</a>|</p>|\xa0|\n', '', time_str)
final_time = re.sub(num, '', final_time) # 比赛时间
return final_time
except:
print("比赛时间获取失败")
比赛网站
这里有一个点就是在过滤后会有两个相同的网站
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
url = bs_url.find('a', rel='nofollow')
final_url = re.sub('<a href="|" rel="nofollow">|</a>|\n', '', str(url))
这里我们可以用取半的方法,取半的长度就是两个链接字符长度和的一半
final_url = final_url[0:int(len(final_url) / 2)]
完整代码
'''
author:C1yas0
time:2021-8-28
'''
import requests
import re
from bs4 import BeautifulSoup
def get_ctftime_running(url):
url_event = "https://ctftime.org/event/"
# ctf = {} # 写入字典用
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
ctf_today = bs_url.find_all('table', width='100%')
for today1 in ctf_today:
today_td = today1.find_all('td')
for today2 in today_td:
today_a = today2.find('a')
if today_a:
# list = [] # 写入字典用
today_a_str = str(today_a)
today_url = re.sub('<a href="/event/|" style="color: #000000">|<img alt="Jeopardy" border="0" rel="tooltip" src="/static/images/ct/1.png" title="Jeopardy"/></a>|\n', '', today_a_str)
new_url = url_event + today_url
# list.append([get_time(new_url, today_url), get_url(new_url)]) # 写入字典用
# ctf[get_name(new_url)] = list # 写入字典用
print(get_name(new_url)+" "+get_time(new_url, today_url)+" " + get_url(new_url))
# print(ctf) # 写入字典用
except:
print("请求失败")
def get_ctftime_upcoming(url):
try:
url_event = "https://ctftime.org/event/"
# ctf = {} # 写入字典用
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
ctf_come = bs_url.find_all('table', class_='table table-striped upcoming-events')
for come1 in ctf_come:
come_tr = come1.find_all('a')
for come2 in come_tr:
# list = [] # 写入字典用
come3 = str(come2)
come4 = come3[0:20]
come_url = re.sub('<a href="/event/', '', come4)
new_url = url_event + come_url
# list.append([get_time(new_url, come_url), get_url(new_url)]) # 写入字典用
# ctf[get_name(new_url)] = list # 写入字典用
print(get_name(new_url)+" "+get_time(new_url, come_url)+" "+get_url(new_url))
# print(ctf) # 写入字典用
except:
print("请求失败")
def get_name(url): # 获取比赛名称
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
name = bs_url.find_all('h2')
final_name = re.sub('<h2>|<i class="icon-play-circle" id="progress" rel="tooltip"></i></h2>|</h2>', '',str(name)) # 比赛名称
return final_name
except:
print("比赛名称获取失败")
def get_time(url,num): # 获取比赛时间
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
times = bs_url.find('div', class_='span10')
time = times.find('p')
time_str = str(time)
final_time = re.sub('<p>|<a href="/event/|.ics|" id="calendar" rel="tooltip">|<img class="svg_icon" id="icon_calendar" src="/static/img/icon_cal.svg"/>|</a>|</p>|\xa0|\n', '', time_str)
final_time = re.sub(num, '', final_time) # 比赛时间
return final_time
except:
print("比赛时间获取失败")
def get_url(url): # 获取比赛网址
try:
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
r = requests.get(url, headers=headers)
bs_url = BeautifulSoup(r.text, 'html.parser')
url = bs_url.find('a', rel='nofollow')
final_url = re.sub('<a href="|" rel="nofollow">|</a>|\n', '', str(url))
final_url = final_url[0:int(len(final_url) / 2)] # 比赛网址
return final_url
except:
print("比赛时间获取失败")
if __name__ == '__main__':
url = "https://ctftime.org"
# get_ctftime_running(url) # 正在举行的比赛
# get_ctftime_upcoming(url) # 即将举行的比赛