python 爬蟲(1):爬取 DDCTF-2018 參賽選手
阿新 • • 發佈:2019-02-14
簡介
這幾天閒來無事,突然想著學習一下 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 '終止爬取,退出程式...'