---
title: Python網路爬蟲入門
description: 中興大學資訊研究社1101學期程式分享會主題社課
tags: Python
---
###### [Python 教學/](/@NCHUIT/py)
# Python 網路爬蟲
> [name=Tatara][time=110,12,23]
## 爬蟲是什麼🤔
當你使用瀏覽器打開一個網頁時,其實是向其伺服器發送 **請求(`request`)**,並且伺服器 **回傳(`response`)** 資料再交給瀏覽器解析與渲染,才出現日常熟悉的網站。而網路爬蟲(web crawler)便是擷取伺服器回傳中我們要的特定資料,並且將過程自動化。
## 請求與回應 Request &Response
![](https://i.imgur.com/CsBcWU9.png)
![](https://i.imgur.com/rbP8KNM.png)
## HTTP & HTTPS
HTTP的全名是超文本傳輸協定(HyperText Transfer Protocol),規範客戶端的請求與伺服器回應的標準,實際上是藉由 TCP 作為資料的傳輸方式。
HTTPS中的S則是(security)。
## 關於html
<table><tr><td><b>H</b>yper<b>T</b>ext <b>M</b>arkup <b>L</b>anguage (超文本標記語言),縮寫:HTML,是一種用於建立網頁的標準<b>標記語言</b>。<br>瀏覽器可以讀取HTML檔案,並將其彩現成<b>視覺化</b>網頁。<br><h6>HTML描述了一個網站的結構語意隨著線索的呈現,使之成為一種標記語言而<em>非程式語言</em>。</h6></td><td><img src='https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/HTML.svg/800px-HTML.svg.png'></td></tr></table>
抓取到的資料會像右圖的html檔,而我們的目的便是找出我們需要的資料在哪個標籤內。
#### 搞不清楚HTTP和HTML的差別?
https://www.geeksforgeeks.org/difference-between-html-and-http/
## 請求Request `HTTP Method`
HTTP的Request方法有[九種](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Methods) 最常用的是 **`GET`** 和 **`POST`**
### `GET` Method
向指定的資源要求資料,類似於查詢操作
以google搜尋為例
先開啟google搜尋頁面 (其實這裡已經做一次請求了)
https://www.google.com/search
按下`F12`可以看到我們送出的`GET`請求(要重新整理)
`GET`的參數會放在URL後面] `https://網址?參數=參數值`-- [headers](https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5), [cookies](https://zh.wikipedia.org/wiki/Cookie), [params (英)](https://en.wikipedia.org/wiki/Query_string)
帶 `params` 的 `get`
https://www.google.com/search?q=klaire_kriel
###### 至於為什麼要加 `search`, 其實是因為 Google 伺服器有個專門為搜索提供 `get` 的頁面被命名為 `search`,但當 `get` 請求沒有 `params` 的時候,它會自動跳向另一個被命名為 `webhp` 的頁面。
### `POST` Method
將要處理的資料提交上去,類似於更新操作。
而當需要更新的資料是較敏感的,就會用`POST`方法把params包起來。
`POST` params-- headers, [cookies](https://zh.wikipedia.org/wiki/Cookie), [data (英)](https://en.wikipedia.org/wiki/POST_(HTTP)#Use_for_submitting_web_forms)
## Python 函式庫 [`requests`](https://requests.readthedocs.io/zh_CN/latest/api.html)
使用python requests 函式庫向伺服器發送請求
### 安裝
```
pip install requests
```
### 語法 [更多方法及語法\ (英)](https://www.w3schools.com/python/module_requests.asp)
#### GET
```python=
requests.get(url[,headers,cookies,params,...])
```
#### POST
```python=
requests.post(url[,headers,cookies,data,...])
```
`[ ]`:選用
省力點也可以這樣
```python=
from requests import request
request("get",url[,headers,cookies,params,...])
```
## 簡單抓取網站資料
#### 一般`GET`
打開colab,抓取[ptt熱門看版網頁](https://www.ptt.cc/bbs/)
```python=
import requests
response = requests.request("GET", url='https://www.ptt.cc/bbs/')#可直接用request函式並在參數內選擇方法(get,post)
print(response.text) #印出資料,也就是文字版的網頁
print(type(response)) #看它的資料型態
print(vars(response)) #看它的屬性
```
#### 帶 `params` 的 `get`
```python=
import requests
url = 'https://www.google.com/search'
payload = { 'q':'klaire_kriel' } #dict
response = requests.request("GET",url=url, params=payload) #關鍵字引數
print(response.text)
```
#### 確認從伺服器傳回的狀態碼 [HTTP狀態碼](https://zh.wikipedia.org/zh-tw/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)
```python=
print(response.status_code) #200 ok
```
#### 判斷伺服器狀態後再抓取
Python requests 函式庫 定義給 Response 的 status 被命名為 status_code
```python=
if response.status_code == requests.codes.ok:
print(response.text)
```
print出來的text很多且很醜?
## 使用 Beautiful Soup 抓取與解析網頁資料
Beautiful Soup 是一個 Python 的函式庫模組,可以快速解析網頁 HTML 碼,從中翠取出我們有興趣的資料、去蕪存菁。
一樣先安裝,但在colab裡都幫你載好了
```
pip install bs4
```
#### Beautiful Soup 基本用法
我們先以簡單的html檔來看bs4的功能
```python=
# 引入 Beautiful Soup 模組
from bs4 import BeautifulSoup as bs
# 原始 HTML 程式碼 假設我們已經有檔案了
html_doc = """
<html><head><title>前進吧!高捷少女</title></head>
<body><h2>K.R.T. GIRLS</h2>
<p>小穹</p>
<p>艾米莉亞</p>
<p>婕兒</p>
<p>耐耐</p>
<a id="link1" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E5%B0%8F%E7%A9%B9">Link 1</a>
<a id="link2" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E8%89%BE%E7%B1%B3%E8%8E%89%E4%BA%9E">Link 2</a>
<a id="link3" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E5%A9%95%E5%85%92 3</a>
<a id="link4" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E8%80%90%E8%80%90">Link 4</a>
</body></html>
"""
# 以 Beautiful Soup 解析 HTML 程式碼
soup = bs(html_doc, 'html.parser') #前項"html_doc"為html的文字資料,後項"'html.parser'"為指定以何種解析器來分析html文字
print(soup)
```
#### 找尋網頁中的元素
`Ctrl + Shift + I`
![](https://i.imgur.com/haX51a0.png)
## 取得節點文字內容
#### 獲取標籤內容
`name`參數方法,可查找所有名為`name`的tag。
```python=
web_title = soup.title #取得網頁標題
print(web_title)
print(web_title.string) #使用字串存取
```
#### 找查元素
選取全部符合條件(標籤節點)的元素 [find_all()](https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#find-all)
```python=
my_girls = soup.find_all('p') #<p></p>標籤
print(my_girls)
```
選取第一個符合條件(標籤節點)的元素 [find](https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#find)
```python=
my_girls = soup.find('p')
```
#### keyword 參數
返回具有keyword的元素
```python=
my_link = soup.find(id='link1')
```
:::spoiler 練習1 在上面範例的html_doc中加入一行 印出所有具有連結的元素
```python=
soup = soup.find_all(id=True)
```
:::
```python=
from bs4 import BeautifulSoup as bs
html_doc = """
<html><head><title>前進吧!高捷少女</title></head>
<body><h2>K.R.T. GIRLS</h2>
<p>小穹</p>
<p>艾米莉亞</p>
<p>婕兒</p>
<p>耐耐</p>
<a id="link1" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E5%B0%8F%E7%A9%B9">Link 1</a>
<a id="link2" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E8%89%BE%E7%B1%B3%E8%8E%89%E4%BA%9E">Link 2</a>
<a id="link3" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E5%A9%95%E5%85%92">Link 3</a>
<a id="link4" href="https://zh.wikipedia.org/wiki/%E9%AB%98%E6%8D%B7%E5%B0%91%E5%A5%B3#%E8%80%90%E8%80%90">Link 4</a>
</body></html>
"""
soup = bs(html_doc, 'html.parser')
#加在這
print(soup)
```
[ BeautifulSoup 官方文檔](https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/)
:::spoiler 練習2 查找 Google 主畫面的超連結文字並印出來。`Hint:文檔get()方法`https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/index.html?highlight=get
```python=
from requests import get
from bs4 import BeautifulSoup as bs
response = get('https://www.google.com/')
soup = bs(response.text) #其中.text是獲得respone中的text屬性,也就是我們的Hyper'Text'
links = soup.find_all('a') #在使用find_all之後,會以list的形式回傳所有符合條件的標籤內容
for link in links:
print(link.get('href'))
```
:::
## CSS 選擇器
###### *[請參閱 BS Doc - CSS 選擇器 (簡)](https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id42)*<br>*[請參閱 w3schools - CSS 選擇器 (英)](https://www.w3schools.com/css/css_selectors.asp)*
#### 漂亮一點?
```python=
print(soup.prettify)
```
## 爬取ptt的表特版中的圖片
https://www.ptt.cc/bbs/Beauty/index.html
![](https://i.imgur.com/GzgXFTE.png)
想想看,要怎麼在爬蟲中OVER 18?
打開F12看看發生什麼事
如果直接get?
```python=
import requests
from bs4 import BeautifulSoup as bs
u = 'https://www.ptt.cc/bbs/Beauty/index.html'
r = requests.get(u)
soup = bs(r.text,'html.parser')
print(soup)
```
會發現我們沒滿18歲
:::spoiler 練習三 夾帶參數'cookies' 取得網頁
```python=
import requests
from bs4 import BeautifulSoup as bs
u = 'https://www.ptt.cc/bbs/Beauty/index.html'
d = {"over18" : '1'}
r = requests.get(url=u,cookies=d)
soup = bs(r.text,'html.parser')
print(soup)
```
:::
好我們現在滿18歲了,現在把表特版中第一篇文章中的圖片的網址抓取下來吧
::: spoiler 練習四
```python=
import requests
from bs4 import BeautifulSoup as bs
u = 'https://www.ptt.cc/bbs/Beauty/M.1640085446.A.E38.html'
d = {"over18" : '1'}
r = requests.post(u,cookies=d)
soup = bs(r.text,'html.parser')
img = soup.find_all('img')
for link in img:
print(link.get('src'))
```
:::
## 補充
### 讀寫檔(之後會教),把圖片下載下來
```python=
import requests
from bs4 import BeautifulSoup as bs
urllist = []
u = 'https://www.ptt.cc/bbs/Beauty/M.1640085446.A.E38.html'
d = {"over18" : '1'}
r = requests.get(u,cookies=d)
soup = bs(r.text,'html.parser')
img = soup.find_all('img')
for link in img:
urllist.append(link.get('src'))
for i,url in enumerate(urllist):
with open (f'{i}.jpg','wb') as f:
f.write(requests.get(url).content)
```
## 回家作業: 選課網頁分析
https://reurl.cc/35dnvV
下載網址中的壓縮檔,解壓縮後練習解析網頁:
通識加選-選擇.html
: 建立一個「"選課號碼":["v_click":"XXX","課程名稱":"XXXX","授課教師":"XXX","上課時間":"XXX","可選餘額":"XX"]」的字典
通識加選-確認.html
: 建立一個「"選課號碼":["v_click":"XXX","課程名稱":"XXXX","授課教師":"XXX","上課時間":"XXX",**"可選餘額":"XX"**]」的字典,其中可選餘額**需自行計算**
通識加選-完成.html
: 建立一個「"選課號碼":["v_click":"XXX","課程名稱":"XXXX","授課教師":"XXX","上課時間":"XXX","可選餘額":"XX",**"結果說明":"XXX"**]」的字典,其中可選餘額**需自行計算**
網址都有註解在html開頭