iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 8
3
AI & Data

Scrapy爬蟲與資料處理30天筆記系列 第 8

[Day 08] Beautiful Soup 解析HTML元素

  • 分享至 

  • xImage
  •  

嗨,第八天了!昨天介紹了網頁HTML的架構,今天就要來說明如何用BeautifulSoup去解析裡面的內容。BeautifulSoup在上一年的鐵人賽我有簡單的說明過了。

:: [Day23]Beautiful Soup網頁解析

那今天要說什麼呢?我們就來解析昨天Google搜尋畫面的內容吧!

import requests
from bs4 import BeautifulSoup

r = requests.get('https://www.google.com/search?q=python3')
soup = BeautifulSoup(r.text, 'lxml')
  • 先引入requests, BeautifulSoup
  • https://www.google.com/search?q=python3為我們要請求的網址,這個頁面為我們在Google搜尋python3出來的頁面(可以看昨天的文章)
  • 把回傳內容裡的文字也就是html內容傳入BeautifulSoup

在昨天的文章中,我們關閉了JS,關閉之後會看到這個畫面:

Imgur

現在來看看裡面的元素吧,先從標題點右鍵檢查:
Imgur

可以看出它在a標籤裡面,但若我們直接抓取所有a標籤,會把葉庫存檔,類似內容等內容也抓到,所以我們往上一層看,會發現a包覆在h3classr的標籤裡面,程式碼:

a_tags = soup.select('h3.r a')
for t in a_tags:
    print(t.text)

可以看出我們找到所有的標題了:
Imgur

來說明一下select()也就是css 選擇器,若有寫過css就能夠理解怎麼去解析它,.&#的用法就是css在用的寫法。其實select()就跟find_all()是一樣的,只是內容的寫法不同,find_all()在上一年文章已經說明過了,這裡就不贅述了,.select('h3.r a')中的h3為標籤名稱.class屬性,所以.後面接class名稱也就是r#id屬性。

  • 注意:select()所得到的內容為一list,跟find_all()一樣,所以若確定只有一個內容可以用select_one()
title = soup.select_one('h3.r a')
print(title.text)

上面程式碼,只會得到Python 3.0 Release | Python.org

  • 注意:因為只會抓一筆,所以它並不是存在list內,不需要用迴圈去取出全部內容,可以直接使用title.text

這樣有理解兩個的差別了嗎?
接下來我們來取得href吧!先來看看a_tag這個變數是什麼內容:

a_tag = soup.select_one('h3.r a')
print(a_tag)
# <a href="/url?q=https://www.python.org/download/releases/3.0/&sa=U&ved=0ahUKEwigs7is6PvdAhXB2LwKHSUqCWoQFggTMAA&usg=AOvVaw0PrtXxN9eChI2u0SKQ7wuS">Python 3.0 Release | Python.org</a>

可以看出來它抓到整個a元素的內容,那href要怎麼得到呢?

print(a_tag['href'])
# /url?q=https://www.python.org/download/releases/3.0/&sa=U&ved=0ahUKEwjo9qPw6PvdAhVV6bwKHQVBDrAQFggTMAA&usg=AOvVaw1-sMTCID-cyLCuxL9Q4fIU

好的,現在得到了這串不知名的href要做什麼呢?

a_tag = soup.select_one('h3.r a')
href = a_tag['href']

googleUrl = 'https://www.google.com'
print(googleUrl + href)
# https://www.google.com/url?q=https://www.python.org/download/releases/3.0/&sa=U&ved=0ahUKEwiBkavx6fvdAhXIvLwKHVstDacQFggTMAA&usg=AOvVaw0qRzzs3ItQQZszDNvtFiet

所得到的內容就是搜尋結果的第一個網頁連結了!不信的話點進去看看?

最後,我們寫一個小小的範例,抓到href後重新更換url重新requests,並將頁面存到html檔案內:

r = requests.get('https://www.google.com/search?q=python3')
soup = BeautifulSoup(r.text, 'lxml')
googleUrl = 'https://www.google.com'
a_list = soup.select('h3.r a')
for a in a_list:
    print('title', a.text)
    print('href', a['href'])
    contentUrl = googleUrl + a['href']
    r = requests.get(contentUrl)
    with open ( a.text + '.html', 'w+') as f:
        f.write(r.text)
        print('saved')

這樣我們就得到每個連結裡的網頁內容了!
透過這個方式我們可以再分別解析網頁內容!
因此,明天我們來試試看如何透過requests&BeautifalSoup爬PTT!


上一篇
[Day 07] 爬蟲前要先理解的HTML架構
下一篇
[Day 09] 實戰:用Requests&bs4 爬PTT (1)
系列文
Scrapy爬蟲與資料處理30天筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
renewang
iT邦新手 5 級 ‧ 2018-12-05 16:28:41

最下面的範例沒有提供 headers 呦...
另外我想問一下,如果 javascript 沒有關掉的話,抓到的網頁會是長的如何?
我用 stackoverflow 提供的解答,用 developer 的工具把 javascript 濾掉,不知道這樣的方法,和你所說的是否有同樣的效果呢? https://stackoverflow.com/questions/13405383/how-to-disable-javascript-in-chrome-developer-tools

plusone iT邦新手 5 級 ‧ 2018-12-05 18:08:27 檢舉

你好,
其實在上面程式碼中可以不需要加入header參數,直接

r = requests.get(contentUrl)

我文章會再修正一下,感謝你。
或是header設定像是:headers={'Content-type': 'text/plain; charset=utf-8'}

關於你提到如果javascript沒有關掉的話,抓到的網頁會是長的如何?的問題,
應該要這樣解釋:
我之所以要示範關閉javascript(第7天),
是因為爬蟲抓到的就是沒有js的內容,除非用工具渲染js(後面文章有提到)不是說因為我們關閉了所以才只會抓到沒有js的內容(有點饒舌)

你上面網址的內容,我在第7天有說明哦https://ithelp.ithome.com.tw/articles/10204082

renewang iT邦新手 5 級 ‧ 2018-12-06 15:39:12 檢舉

謝謝...我還是有點看不懂 js 的部分,或許看到後面的時候再來請教吧!

我要留言

立即登入留言