Python爬蟲之解析網頁


常用的類庫為lxml, BeautifulSoup, re(正則)

以獲取豆瓣電影正在熱映的電影名為例,url='https://movie.douban.com/cinema/nowplaying/beijing/'

網頁分析

部分網頁源碼

<ul class="lists">
                    <li
                        id="3878007"
                        class="list-item"
                        data-title="海王"
                        data-score="8.2"
                        data-star="40"
                        data-release="2018"
                        data-duration="143分鍾"
                        data-region="美國 澳大利亞"
                        data-director="溫子仁"
                        data-actors="傑森·莫瑪 / 艾梅柏·希爾德 / 威廉·達福"
                        data-category="nowplaying"
                        data-enough="True"
                        data-showed="True"
                        data-votecount="105013"
                        data-subject="3878007"
                    >
                        

分析可知我們要的電影名稱信息在li標簽的data-title屬性里

下面開始寫代碼

爬蟲源碼展示

import requests
from lxml import etree              # 導入庫
from bs4 import BeautifulSoup
import re

import time

# 定義爬蟲類
class Spider():
    def __init__(self):
        self.url = 'https://movie.douban.com/cinema/nowplaying/beijing/'

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
        }
        r = requests.get(self.url,headers=self.headers)
        r.encoding = r.apparent_encoding
        self.html = r.text

    def lxml_find(self):
        '''用lxml解析'''
        start = time.time()						# 三種方式速度對比
        selector = etree.HTML(self.html)        # 轉換為lxml解析的對象
        titles = selector.xpath('//li[@class="list-item"]/@data-title')    # 這里返回的是一個列表
        for each in titles:
            title = each.strip()        # 去掉字符左右的空格
            print(title)
        end = time.time()
        print('lxml耗時', end-start)

    def BeautifulSoup_find(self):
        '''用BeautifulSoup解析'''
        start = time.time()
        soup = BeautifulSoup(self.html, 'lxml')   # 轉換為BeautifulSoup的解析對象()里第二個參數為解析方式
        titles = soup.find_all('li', class_='list-item')
        for each in titles:
            title = each['data-title']
            print(title)
        end = time.time()
        print('BeautifulSoup耗時', end-start)

    def re_find(self):
        '''用re解析'''
        start = time.time()
        titles = re.findall('data-title="(.+)"',self.html)
        for each in titles:
            print(each)
        end = time.time()
        print('re耗時', end-start)

if __name__ == '__main__':
    spider = Spider()
    spider.lxml_find()
    spider.BeautifulSoup_find()
    spider.re_find()

輸出結果

海王
無名之輩
無敵破壞王2:大鬧互聯網
狗十三
驚濤颶浪
毒液:致命守護者
憨豆特工3
神奇動物:格林德沃之罪
恐龍王
老爸102歲
生活萬歲
進擊的男孩
摘金奇緣
亡命救贖
一百年很長嗎
雲上日出
誰是壞孩子
照相師
緣·夢
網絡謎蹤
龍貓
印度合伙人
綠毛怪格林奇
最萌警探
春天的馬拉松
lxml耗時 0.007623910903930664
海王
無名之輩
無敵破壞王2:大鬧互聯網
狗十三
驚濤颶浪
毒液:致命守護者
憨豆特工3
神奇動物:格林德沃之罪
恐龍王
老爸102歲
生活萬歲
進擊的男孩
摘金奇緣
亡命救贖
一百年很長嗎
超時空大冒險
天渠
愛不可及
二十歲
你好,之華
冒牌搭檔
鐵甲戰神
克隆人
恐怖快遞
中國藍盔
阿凡提之奇緣歷險
名偵探柯南:零的執行人
為邁克爾·傑克遜鑄造雕像
再見仍是朋友
心迷宮
淡藍琥珀
阿拉姜色
兩個俏公主
雲上日出
誰是壞孩子
照相師
緣·夢
網絡謎蹤
龍貓
印度合伙人
綠毛怪格林奇
最萌警探
春天的馬拉松
BeautifulSoup耗時 0.061043500900268555
海王
無名之輩
無敵破壞王2:大鬧互聯網
狗十三
驚濤颶浪
毒液:致命守護者
憨豆特工3
神奇動物:格林德沃之罪
恐龍王
老爸102歲
生活萬歲
進擊的男孩
摘金奇緣
亡命救贖
一百年很長嗎
超時空大冒險
天渠
愛不可及
二十歲
你好,之華
冒牌搭檔
鐵甲戰神
克隆人
恐怖快遞
中國藍盔
阿凡提之奇緣歷險
名偵探柯南:零的執行人
為邁克爾·傑克遜鑄造雕像
再見仍是朋友
心迷宮
淡藍琥珀
阿拉姜色
兩個俏公主
雲上日出
誰是壞孩子
照相師
緣·夢
網絡謎蹤
龍貓
印度合伙人
綠毛怪格林奇
最萌警探
春天的馬拉松
re耗時 0.0004856586456298828

代碼說明

1. lxml

lxml是通過xpath來查找

使用前需使用調用ertee.HTML()方法('()'內填HTML代碼)生成一個可查找的對象

常用xpath語法如下

// 兩個斜杠為向下查找孫子標簽

/ 一個斜杠為查找直接兒子標簽

[] 方括號內填標簽屬性,如查找class屬性為name的a標簽,格式為a[@class="name"]

/text() 取出標簽的內容,如查找網頁中的 <a class="name">KAINHUCK</a> 中的KAINHUCK,格式為//a[@class="name"]/text()

/@attr 取出標簽的屬性,如查找網頁中的 <a class="name">KAINHUCK</a> 中的class屬性值name,格式為//a[@class="name"]/@class

2. BeautifulSoup

使用前需先將HTML轉換為課查找對象,格式為

BeautifulSoup(html, 'lxml')

html 為HTML代碼, 后面的參數為轉換方法(其他方法有'html.parser' , 'html5lib', 推薦使用'lxml')

查找方法

info = find('a', id='kain') 查找第一個id屬性為kain的a標簽,並存進info變量中(其他標簽同理)

find_all('a', class_='name') 查找所有class屬性為name的a標簽(注:class屬性需寫成'class_')

info.p.text 獲取第一個id屬性為kain的a標簽下的p標簽的內容(info為上面例子里的info,其他同理)

info.p['name'] 獲取第一個id屬性為kain的a標簽下的p標簽的name屬性值(info為上面例子里的info,其他同理)

當代碼中有很多同級標簽時

<p class='info-list'>
       <a class='name'>text1</a>
       <a class='name'>text2</a>
       <a class='name'>text3</a>
       <a class='name'>text4</a>
   </p>

示例代碼如下

from bs4 import BeautifulSoup

html = '''
   <p class='info-list'>
       <a class='name'>text1</a>
       <a class='name'>text2</a>
       <a class='name'>text3</a>
       <a class='name'>text4</a>
   </p>
'''
soup = BeautifulSoup(html, 'lxml')
texts = soup.find('p', class_='info-list')
print(texts.contents[1].text)	# 輸出text1
print(texts.contents[2].text)	# 輸出text2
print(texts.contents[3].text)	# 輸出text3
print(texts.contents[4].text)	# 輸出text4

注意:不是從0開始

3. re(正則表達式)

正則表達式內容較多,大家可以參考這里

總結

使用lxml查找時可以在目標網頁按F12調出開發者窗口然后再在按Ctrl+f查找,在查找欄里輸入你的xpath語法可以檢查是否能找到對應內容

可以從看例子的輸出中看出三種方法的速度

lxml耗時 0.007623910903930664

BeautifulSoup耗時 0.061043500900268555

re耗時 0.0004856586456298828

對以上三種最常用的解析網頁的方法做個對比

lxml BeautifulSoup re
語法難易度 簡單 簡單 復雜
查找速度 較快

綜上,對於網頁內容的解析,這里推薦新手使用lxml方法,而對速度有要求就使用正則表達式(入門有點困難)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM