1. 程式人生 > >python 爬蟲(1):爬取 DDCTF-2018 參賽選手

python 爬蟲(1):爬取 DDCTF-2018 參賽選手

簡介

這幾天閒來無事,突然想著學習一下 python 爬蟲,也可以用來練習一下 python。剛好這兩天報名參加了 DDCTF-2018 比賽,在比賽官網的挑戰者頁面可以看到參賽者,不如就爬取一下所有的參賽者資訊吧。

平時用 python 不多,這也是我第一次寫 python 爬蟲,難免有不足的地方,以後繼續進步。本文使用了 urlib2 + Beautiful soup,同時使用 xlsxwriter 將獲取到的參賽者資訊儲存 excel 表格中,希望對一些 python 爬蟲入門的朋友有一點幫助。

分析

開啟官網的挑戰者頁面,如下:

挑戰者頁面

可見每個參賽者都列出了暱稱、大學以及年級三項資訊,這個表格的原始碼如下:

<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 '終止爬取,退出程式...'

爬取結果

執行結果

成果展示