[Python 小東西] 爬取英文單字列表網站

這次我想爬取 majortests 中的英文列表。這個網站的組成蠻簡單的(雖然廣告很多),標籤也很一致整齊,很適合做為爬取單字的爬蟲練習。此為我的 github page 上 2021 年 2 月搬運過來之文章,並且有做一些語句上的修正。

前置作業-觀察

在爬網頁之前,要先觀察網頁的結構。這個網頁中的單字表有分 10 個單元,目的是把這幾個單字表的單字都通通抓取下來,因此我們會需要這 10 個單字表的網址。

實際查看後發現,這幾個單字表的網址變化蠻規律且簡單的:

https://www.majortests.com/word-lists/word-list-01.html 一直到 https://www.majortests.com/word-lists/word-list-10.html ,能夠藉由更改 word-list- 後方的數字達到造訪每個單字表的目的。

另外單字表在 html 標籤中的位置,對照實際的單字表,可以觀察到單字表在 table 標籤中,它們的 class 都是 wordlist,而單字本身和解釋,分別在 tr 標籤中用 thtd 隔開,是一個很整齊的結構,爬起來不會太麻煩。

功能

接著思考爬蟲,有幾項基本的功能要設計:

  • 生成網址
  • 改變 header
  • 獲取網頁 tag 結構
  • 抓取單字
  • 爬蟲
  • 存成 csv 格式

要 import 的有:

from bs4 import BeautifulSoup
import time
import csv
import requests

生成網址

因為標號是 01, 02, ….,09,雖有十個單字表,但這裡主要想實作爬蟲,因此將過程再弄得更簡單易點,這次我們先只抓取 9 個單字表。
URL = "https://www.majortests.com/word-lists/word-list-0{0}.html"

設一個陣列 urls,用迴圈生成編號從 1 到 9 的網址,並將生成的網址放進裡面。

def generate_urls(url, start, end):
    urls = []
    for i in range(start, end + 1):
        urls.append(url.format(i))
    return urls

改變 header

網站有可能會發現有奇怪的東西(例如一個 Python 程式)在拋出請求,為了不讓網站發現,需要一個 function 去將 header 更改成瀏覽器的樣子。

網路上查會發現有很多不同的寫法,複製任何一種查得到的 header 都可以,只要能順利讓網站接受即可。

def change_get(url):
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
           'AppleWebKit/537.36 (KHTML, like Gecko)'
           'Chrome/63.0.3239.132 Safari/537.36'}
    return requests.get(url, headers = headers)

獲取網頁 tag 結構

這裡沒什麼特別的,僅是把 html 結構抓下來。

def get_html(str):
    return BeautifulSoup(str, "lxml")

抓取單字

接下來進入到重點部分,如何抓取單字。開始利用 BeautifulSoup 所獲得的 tag 結構,去挖需要的東西。先前我們已經分析過結構了,由於它們的 class 都是 wordlist,本身很好鎖定,使用 find_all() 抓取。再來單字、解釋們分別在 tr 中的 thtd 標籤內。

def get_words(soup, file):
    words = []
    count = 0
    
    for table in soup.find_all(class_ = "wordlist"):
        count += 1
        for word_entry in table.find_all("tr"):
            newWord = []
            newWord.append(file)
            newWord.append("Group " + str(count))
            newWord.append(word_entry.th.text)
            newWord.append(word_entry.td.text)
            words.append(newWord)
    return words

爬蟲

解決完單字處理後,來寫一小段簡單的爬蟲。利用以上的 function,將所要爬的網址改變 header 後,取得該網站結構,並且利用這個結構去找自己要的 tag,並儲存單字在自己設的陣列裡面。

def web_scraping(urls):
    eng_words = []
    
    for url in urls:
        file = url.split("/")[-1].split(".")[-2].replace('-', ' ') #利用 url 字串改成檔案來源名稱
        print("scrape the file : " + file)
        r = change_get(url)
        if r.status_code == requests.codes.ok:
            soup = get_html(r.text)         #取得 html 字串
            words = get_words(soup, file)    #html 字串的處理
            eng_words = eng_words + words    
            print("wait for 5 seconds...")
            time.sleep(5)
        else:
            print("HTTP requests error")
    return eng_words

存成 csv 格式

上方差不多把事情做完了,記得將結果印出或是存成一個檔案。這裡就是採用先前存好的 filewords,逐一寫入檔案內。

def to_csv(words, file):
    with open(file, "w+", newline = "", encoding = "utf-8") as fp:
        writer = csv.writer(fp)
        for word in words:
            writer.writerow(word)

最終主程式呼叫

if __name__ == "__main__":
    urls = generate_urls(URL, 1, 9)
    eng_words = web_scraping(urls)
    for item in eng_words:
        print(item)
    to_csv(eng_words, "words.csv")

當然要看一下執行結果囉:

結果抓完後發現有很多不會的單字QQ


參考資料

讓我知道你在想什麼!

Picture of ALEX

ALEX

藍白拖愛好者,一事無成話偏多

Recent Posts

C++

NLP