通过python爬虫获取ctftime的ctf比赛时间(详解+源码)

查看结果

源码在最下面,但如果真正想要学习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) # 即将举行的比赛

猜你喜欢

转载自blog.csdn.net/weixin_46706771/article/details/119973505