欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python 爬虫(1):爬取 DDCTF-2018 参赛选手

程序员文章站 2022-05-12 13:54:49
...

简介

这几天闲来无事,突然想着学习一下 python 爬虫,也可以用来练习一下 python。刚好这两天报名参加了 DDCTF-2018 比赛,在比赛官网的挑战者页面可以看到参赛者,不如就爬取一下所有的参赛者信息吧。

平时用 python 不多,这也是我第一次写 python 爬虫,难免有不足的地方,以后继续进步。本文使用了 urlib2 + Beautiful soup,同时使用 xlsxwriter 将获取到的参赛者信息保存 excel 表格中,希望对一些 python 爬虫入门的朋友有一点帮助。

分析

打开官网的挑战者页面,如下:

python 爬虫(1):爬取 DDCTF-2018 参赛选手

可见每个参赛者都列出了昵称、大学以及年级三项信息,这个表格的源代码如下:

<table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <td><b>昵称</b></td>
                        <td class="d-none d-md-table-cell d-lg-table-cell"><b>大学</b></td>
                        <td class="d-none d-md-table-cell d-lg-table-cell"><b>年级</b></td>
                    </tr>
                </thead>
                <tbody>

                    <tr>
                        <td>

                            <a href="/team/84">HONKONE</a>

                        </td>
                        <td class="d-none d-md-table-cell d-lg-table-cell">


                                <span>
                                    电子科技大学成都学院
                                </span>


                        </td>
                        <td class="d-none d-md-table-cell d-lg-table-cell">
                            <span>大四</span>
                        </td>
                    </tr>

                    ...
                    ...                 

                    <tr>
                        <td>

                            <a href="/team/152">十九岁</a>

                        </td>
                        <td class="d-none d-md-table-cell d-lg-table-cell">


                                <span>
                                    宿州学院
                                </span>


                        </td>
                        <td class="d-none d-md-table-cell d-lg-table-cell">
                            <span>大一</span>
                        </td>
                    </tr>

                </tbody>
</table>

因此利用 Beautiful soup 获取到表格的每一个 <tr></tr> 标签,再获取其所有 Navigable String 即可。

但是这样仅仅获取到一个页面的参赛者信息,剩余的其它页面的参赛者信息怎么获取呢?观察页面 url 后发现,不同的参赛者页面的 url 的构造都是 http://ddctf.didichuxing.com/teams/ + page,page 的值为 1, 2, 3 …

同样分析发现,当页面表格仅仅有一行时,即一个 <tr></tr> 标签时,说明该页面没有参赛者,也即是已经爬取完所有参赛者了。由此可以终止爬取。

代码

# -*- coding: UTF-8 -*-

import urllib2
from bs4 import BeautifulSoup
import xlsxwriter
import os
import sys
reload(sys)
sys.setdefaultencoding('utf-8')


URL_BASE = 'http://ddctf.didichuxing.com/teams/'
ALL_CHALLENGER = []     # 存放所有选手信息


def save_to_xlsx():
    workbook = xlsxwriter.Workbook('DDCTF-2018-challengers.xlsx')
    worksheet = workbook.add_worksheet('first_sheet')

    title_format = workbook.add_format({'bold':True, 'font_size':18, 'bg_color':'cccccc'})
    worksheet.write_row('A1', ['昵称', '大学', '年级'], title_format)
    worksheet.set_column('A:A', 30)     # 设置A列列宽为 30
    worksheet.set_column('B:B', 20)
    worksheet.set_column('C:C', 40)

    row = 1
    for challenger in ALL_CHALLENGER:
        worksheet.write_row(row, 0, challenger)
        row += 1
    workbook.close()

    print '所有选手信息已保存至 ' + os.getcwd() + '\DDCTF-2018-challengers.xlsx'


def get_info(all_challengers):
    global ALL_CHALLENGER
    for challenger in all_challengers:
        if challenger.find('a'):    # 存在选手姓名
            strs = list(challenger.stripped_strings)
            if len(strs) == 3:
                ALL_CHALLENGER.append([strs[0], strs[2], strs[1].strip()])
            elif len(strs) == 2:    # 院校可以刻意构造为空,此时要特殊处理
                ALL_CHALLENGER.append([strs[0], strs[1], ''])


def spider(url):
    req = urllib2.Request(url)
    try:
        response = urllib2.urlopen(req)
    except urllib2.URLError, e:
        if hasattr(e, 'reason'):            # 页面加载错误,同样应该已经爬取完所有参赛者信息
            print '加载页面 ' + url + ' 失败,失败原因:' + e.reason
            return False
    soup = BeautifulSoup(response.read().decode('utf-8'), "html.parser")

    all_challengers = soup.find_all('tr')
    if len(all_challengers) <= 1:           # 页面没有任何参赛者,说明已经爬取完所有参赛者信息
        print '页面 ' + url + ' 无选手信息'
        return False
    get_info(all_challengers)

    print '成功抓取页面 ' + url + ' !'
    return True


if __name__=="__main__":
    page = 1
    while 1:
        if not spider(URL_BASE + str(page)):
            break
        page += 1

    save_to_xlsx()
    print '终止爬取,退出程序...'

爬取结果

python 爬虫(1):爬取 DDCTF-2018 参赛选手

python 爬虫(1):爬取 DDCTF-2018 参赛选手