1. 程式人生 > >從零開始寫Python爬蟲 --- 1.6 爬蟲實踐: DOTA'菠菜'結果查詢

從零開始寫Python爬蟲 --- 1.6 爬蟲實踐: DOTA'菠菜'結果查詢

說起來目錄裡面本來是準備雙色球資訊查詢的,但是我一點都不懂這個啊,恰好身邊有個老賭棍,沉迷Dota飾品交易,俗稱 “菠菜”。老賭棍啊,老賭棍,能不能不要每天我說天台見。。。
這次的爬蟲功能十分的簡答,主要目的是延展一下bs4庫的使用。

目標分析:

看一看網站裡的資訊是怎麼排列的:


和上一次一樣 我們使用開發者工具,快速定位到比賽結果的div中:


有了上一次爬取百度貼吧的經驗。我們很容易就能發現,每一場比賽的資訊都儲存在:

<div class="matchmain bisai_qukuai">

這個div中。
這樣我們先利用bs4庫的findall()方法抓取到每個div,
再迴圈遍歷出每一條我們需要的資訊就大功告成了!

程式碼的實現:

抓取頭:

依舊是我們經常用的抓網頁到本地的程式碼框架,

def get_html(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return " ERROR "

主要處理函式:

def print_result(url):
    '''
    查詢比賽結果,並格式化輸出!
    '''
html = get_html(url) soup = bs4.BeautifulSoup(html,'lxml') match_list = soup.find_all('div', attrs={'class': 'matchmain bisai_qukuai'}) for match in match_list: time = match.find('div', attrs={'class': 'whenm'}).text.strip() teamname = match.find_all('span', attrs={
'class': 'team_name'}) #由於網站的構造問題,隊名有的時候會不顯示,所以我們需要過濾掉一些註釋,方法如下: if teamname[0].string[0:3] == 'php': team1_name = "暫無隊名" else: team1_name = teamname[0].string # 這裡我們採用了css選擇器:比原來的屬性選擇更加方便 team1_support_level = match.find('span', class_='team_number_green').string team2_name = teamname[1].string team2_support_level = match.find('span', class_='team_number_red').string print('比賽時間:{},\n 隊伍一:{} 勝率 {}\n 隊伍二:{} 勝率 {} \n'.format(time,team1_name,team1_support_level,team2_name,team2_support_level))

這裡有些內容要想說一下:

  • bs4css選擇器的使用:

原來我們在文件中查詢tag的時候,總是習慣使用這個方法:

find_all('name',attrs={})


這個方法的的確是很方便的幫我們定位元素,
之前的查詢中,我們只用到attrs={}字典中的一個class值。
如果單單通過class屬性來定位我們有更好的方式:css選擇器:

語法:

soup.find_all("a", class_="xxx")


這樣我們就能迅速的找到soup中的class為‘xxx’的元素了

  • Comment型別的註釋檔案:

這次我們在爬取的時候,由於網站可能沒做好,有的隊伍名字查詢不到,就會顯示一個php的查詢註釋:

<div class="teamtext">
<span class="team_name"><?php phpinfo(); ?></span>
</div>`

這裡我選擇了硬編碼的方式來解決:

#由於網站的構造問題,隊名有的時候會不顯示,所以我們需要過濾掉一些註釋,方法如下:
        if teamname[0].string[0:3] == 'php':
            team1_name = "暫無隊名"
        else:
            team1_name = teamname[0].string

由於是十分小的專案,可以這樣解決,但是如果是較大,
並且需要複用的情況,
我們來看看推薦的做法:

html = '''
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
'''
#可以看到,a標籤下的內容是一個註釋型別,但是如果我們直接輸出它的話
#會輸把註釋符號去掉的 Elsie:

print(soup.a.string) #Elsie

#所以為了過濾掉註釋型別,我們可以這樣做:

if type(soup.a.string)==bs4.element.Comment:
    //TO DO
#上面通過一個簡單的型別判斷解決了這個問題。

整體程式碼:

'''
爬取Dota菠菜結果資訊
使用 requests --- bs4 線路
Python版本: 3.6
OS: mac os 12.12.4
'''

import requests
import bs4

def get_html(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return " ERROR "

def print_result(url):
    '''
    查詢比賽結果,並格式化輸出!
    '''
    html = get_html(url)
    soup =  bs4.BeautifulSoup(html,'lxml')
    match_list = soup.find_all('div', attrs={'class': 'matchmain bisai_qukuai'})
    for match in match_list:
        time = match.find('div', attrs={'class': 'whenm'}).text.strip()
        teamname = match.find_all('span', attrs={'class': 'team_name'})
       
        
        #由於網站的構造問題,隊名有的時候會不顯示,所以我們需要過濾掉一些註釋,方法如下:
        if teamname[0].string[0:3] == 'php':
            team1_name = "暫無隊名"
        else:
            team1_name = teamname[0].string
        
        # 這裡我們採用了css選擇器:比原來的屬性選擇更加方便
        team1_support_level = match.find('span', class_='team_number_green').string

        team2_name = teamname[1].string
        team2_support_level = match.find('span', class_='team_number_red').string

        print('比賽時間:{},\n 隊伍一:{}      勝率 {}\n 隊伍二:{}      勝率 {} \n'.format(time,team1_name,team1_support_level,team2_name,team2_support_level))



def main():
    url= 'http://dota2bocai.com/match'
    print_result(url)

if __name__ == '__main__':
    main()

爬取結果:




經過這兩個小例子,大家也可以開始動手去寫自己的爬蟲了
你可能會遇到很多小問題,不要畏懼,一點一點的去解決
看著debug資訊,遇到不懂的就去Google,其實我們遇到的很多問題,
前人都已經遇到過,並且大多數時候都有很好地解決辦法。
如果還是不能解決,歡迎在我這裡留言~