Skip to content

Instantly share code, notes, and snippets.

@x1001000
Last active December 30, 2022 08:13
Show Gist options
  • Save x1001000/8cc71b54264152030ba45df753217d8f to your computer and use it in GitHub Desktop.
Save x1001000/8cc71b54264152030ba45df753217d8f to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/x1001000/8cc71b54264152030ba45df753217d8f/web_crawler.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WcyEKCatFug3"
},
"source": [
"1. 從 [博客來 > 中文書 > 分類總覽頁](https://www.books.com.tw/web/sys_sublistb/books/?loc=subject_012) 觀察到分類範圍有大中小三層,而每個小分類網址中都有XXYYZZ,XX為第一層編號,YY為第二層編號,ZZ為第三層編號,例如 [文學小說 > 翻譯文學 > 日本文學](https://www.books.com.tw/web/sys_bbotm/books/010101) 的網址為 www.books.com.tw/web/sys_bbotm/books/010101\n",
"1. 設計三層巢狀迴圈,從010101開始抓資料,到010109發現過頭了,再到010201,依此類推,但這方法不好寫,不如用 [re](https://docs.python.org/3/library/re.html) 直接把分類總覽頁中有連續六個數字的網址全部找出來\n",
"1. 有些只有第二層沒有第三層的中分類,例如 [文學小說 > 溫馨/療癒小說](https://www.books.com.tw/web/books_bmidm_0111/?loc=P_0001_2_011) 的網址就沒有XXYYZZ,要設法另外找\n",
"1. 用迴圈遍訪找到的分類網址,把每個分類的書籍資料逐頁(100本/頁)彙整在一個 [pandas.DataFrame](https://oranwind.org/python-pandas-ji-chu-jiao-xue/),最後匯出一個 csv 檔\n",
"1. 依序執行以下 code cell 或從 Runtime 選單 Run all,全站爬完要很久,可以隨時按停止,若電腦進入休眠或離線 Runtime 會被收回,但 csv 檔們仍會在 Google Drive\n",
"1. 博客來網站會對持續讀取網頁的連線停止回應,若爬蟲繼續嘗試連線則會被封鎖,必須重置 Runtime 換 IP 才能解決,經實測發現,博客來網站停止回應時,讓爬蟲裝死一分鐘,就能重新得到回應"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bkrYZIoPipdn",
"outputId": "d1bd8dbd-e3bc-472d-9feb-6db40bf8da8a"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Mounted at /content/drive\n"
]
}
],
"source": [
"# 掛載 Google Drive 於目前 Runtime 下,程式匯出的 csv 檔們就可以存進 Google Drive,再用 Google Sheets 開啟\n",
"from google.colab import drive\n",
"drive.mount('/content/drive')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7WY79UqlxNaC"
},
"outputs": [],
"source": [
"# 下 Linux 指令在 Google Drive 新增資料夾\n",
"! mkdir drive/MyDrive/博客來-中文書"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SGu0J95d0Vg4"
},
"outputs": [],
"source": [
"# 匯入所需的 Python 套件\n",
"import requests\n",
"from bs4 import BeautifulSoup\n",
"import re\n",
"import pandas as pd\n",
"from time import sleep"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hFgwlAz40oYx",
"outputId": "cfb10f6a-b9b1-4f0f-edab-5ef2d8d16d7d"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"找到945個小分類網址,另外找到64個沒有小分類的中分類網址,皆儲存於urls中\n"
]
}
],
"source": [
"# 找出全部博客來中文書的分類網址\n",
"r = requests.get('https://www.books.com.tw/web/sys_sublistb/books/?loc=subject_012')\n",
"urls = []\n",
"soup = BeautifulSoup(r.text)\n",
"for link in soup.find_all('a'):\n",
" url = link.get('href')\n",
" if re.search(r'/\\d\\d\\d\\d\\d\\d/', url):\n",
" urls.append(url)\n",
"n = len(urls)\n",
"for mid in r.text.split('</th>'):\n",
" if '<ul></ul>' in mid:\n",
" urls.append(BeautifulSoup(mid).find('a').get('href'))\n",
"print(f'找到{n}個小分類網址,另外找到{len(urls)-n}個沒有小分類的中分類網址,皆儲存於urls中')\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "g9DiHTgCVJU3",
"outputId": "444f63cc-dad0-4fe0-a005-19357037f505"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"博客來-中文書>文學小說>翻譯文學>日本文學 Page:1.2.3.4.5.6.7.8.9.10.11.12.13.14.✅\n",
"博客來-中文書>文學小說>翻譯文學>韓國文學 Page:1.✅\n",
"博客來-中文書>文學小說>翻譯文學>亞洲文學 Page:1.✅\n",
"博客來-中文書>文學小說>翻譯文學>美國文學 Page:1.2.3.4.5.6.7.8.✅\n",
"博客來-中文書>文學小說>翻譯文學>南美文學 Page:1.✅\n",
"博客來-中文書>文學小說>翻譯文學>英國文學 Page:1.2.3.4.5.✅\n",
"(暫停一分鐘)\n",
"博客來-中文書>文學小說>翻譯文學>德國文學 Page:1.✅\n",
"博客來-中文書>文學小說>翻譯文學>法國文學 Page:1.2.3.✅\n",
"博客來-中文書>文學小說>翻譯文學>其他地區 Page:1.2.3.4.✅\n",
"博客來-中文書>文學小說>華文創作>散文 Page:1.2.3.4.5.6.7.8.9.10.11.12.13.14.✅\n",
"博客來-中文書>文學小說>華文創作>小說 Page:1.2.3.4.5.6.7.8.9.10.(暫停一分鐘).(暫停一分鐘).11.✅\n",
"博客來-中文書>文學小說>華文創作>飲食文學 Page:1.✅\n",
"博客來-中文書>文學小說>華文創作>旅遊文學 Page:1.✅\n",
"博客來-中文書>文學小說>華文創作>自然書寫 Page:1.✅\n",
"博客來-中文書>文學小說>華文創作>報導文學 Page:1.✅\n",
"博客來-中文書>文學小說>詩>華文現代詩 Page:1.2.3.4.5.✅\n",
"博客來-中文書>文學小說>詩>外國詩 Page:1.2.✅\n",
"博客來-中文書>文學小說>文學研究>華文文學研究 Page:1.2.3.4.5.✅\n",
"博客來-中文書>文學小說>文學研究>外國文學研究 Page:1.2.✅\n",
"博客來-中文書>文學小說>文學研究>文學史 Page:1.✅\n",
"博客來-中文書>文學小說>文學研究>作家傳記 Page:1.✅\n",
"博客來-中文書>文學小說>中國古典文學>經史子集 Page:1.✅\n",
"博客來-中文書>文學小說>中國古典文學>古典小說 Page:1.(暫停一分鐘).2.✅\n",
"博客來-中文書>文學小說>中國古典文學>古典文學 Page:1.2.✅\n",
"博客來-中文書>文學小說>中國古典文學>詩詞曲賦 Page:1.2.3.✅\n",
"博客來-中文書>文學小說>國學常識>作文、創作 Page:1.✅\n",
"博客來-中文書>文學小說>國學常識>字詞分析 Page:1.✅\n",
"博客來-中文書>文學小說>世界經典文學>神話、傳說 Page:1.✅\n",
"博客來-中文書>文學小說>世界經典文學>歐美經典文學 Page:1.2.3.4.✅\n",
"博客來-中文書>文學小說>世界經典文學>日本古典文學 Page:1.✅\n",
"博客來-中文書>文學小說>世界經典文學>其他經典文學 Page:1.✅\n",
"博客來-中文書>文學小說>懸疑、推理小說>歐美懸疑、推理小說 Page:1.2.3.4.5.✅\n",
"博客來-中文書>文學小說>懸疑、推理小說>日本懸疑、推理小說 Page:1.2.3.4.5.(暫停一分鐘).6.✅\n",
"博客來-中文書>文學小說>懸疑、推理小說>華文懸疑、推理小說 Page:1.2.3.✅\n",
"博客來-中文書>文學小說>科幻、奇幻小說>歐美科幻、奇幻小說 Page:1.2.3.4.5.✅\n",
"博客來-中文書>文學小說>科幻、奇幻小說>日本科幻、奇幻小說 Page:1.✅\n",
"博客來-中文書>文學小說>科幻、奇幻小說>其他科幻、奇幻小說 Page:1.2.3.4.5.6.7.✅\n",
"博客來-中文書>文學小說>恐怖、驚悚小說>歐美恐怖、驚悚小說 Page:1.✅\n",
"博客來-中文書>文學小說>恐怖、驚悚小說>日本恐怖、驚悚小說 Page:1.✅\n",
"博客來-中文書>文學小說>恐怖、驚悚小說>其他恐怖、驚悚小說 Page:1.2.3.4.✅\n",
"博客來-中文書>文學小說>羅曼史、言情小說>華文羅曼史 Page:1.2.3.4.(暫停一分鐘).5.6.7.8.9.10.11.12.13.14.15.16.✅\n",
"博客來-中文書>文學小說>羅曼史、言情小說>外國羅曼史 Page:1.✅\n",
"博客來-中文書>文學小說>歷史、武俠小說>華文歷史小說 Page:1.2.3.✅\n",
"博客來-中文書>文學小說>歷史、武俠小說>日本歷史小說 Page:1.✅\n",
"博客來-中文書>文學小說>歷史、武俠小說>外國歷史小說 Page:1.✅\n",
"博客來-中文書>文學小說>歷史、武俠小說>金庸武俠小說 Page:1.✅\n",
"博客來-中文書>文學小說>歷史、武俠小說>其他武俠小說 Page:1.2.3.✅\n",
"博客來-中文書>商業理財>傳記>人物傳記 Page:1.2.✅\n",
"博客來-中文書>商業理財>傳記>企業傳記 Page:1.✅\n",
"博客來-中文書>商業理財>管理與領導>管理學 Page:1.✅\n",
"博客來-中文書>商業理財>管理與領導>組織/管理 Page:(暫停一分鐘).1.2.3.✅\n",
"博客來-中文書>商業理財>管理與領導>領導/帶人 Page:1.2.✅\n",
"博客來-中文書>商業理財>管理與領導>經營策略 Page:1.2.3.✅\n",
"博客來-中文書>商業理財>管理與領導>創業開店 Page:1.2.✅\n",
"博客來-中文書>商業理財>管理與領導>各行各業經營 Page:1.2.✅\n",
"博客來-中文書>商業理財>專業管理實務>專案管理 Page:1.✅\n",
"博客來-中文書>商業理財>專業管理實務>人力資源管理 Page:1.✅\n",
"博客來-中文書>商業理財>專業管理實務>財務管理 Page:1.✅\n",
"博客來-中文書>商業理財>專業管理實務>資訊管理 Page:1.✅\n",
"博客來-中文書>商業理財>專業管理實務>生產/作業管理 Page:1.✅\n",
"博客來-中文書>商業理財>專業管理實務>品質管理 Page:"
]
}
],
"source": [
"# 遍訪找到的分類網址,逐頁彙整書籍資料,DataFrame 轉 csv,存至 Google Drive\n",
"for url in urls:\n",
" while True:\n",
" r = requests.get(url)\n",
" if r.status_code == 200:\n",
" soup = BeautifulSoup(r.text)\n",
" filename = soup.title.string.replace('/', '、')\n",
" print(filename, end=' Page:')\n",
" df = pd.DataFrame(columns=['書名', '作者', '出版日期', '內容介紹', '網址'])\n",
" p = 1\n",
" break\n",
" else:\n",
" print('(暫停一分鐘)')\n",
" sleep(60)\n",
" while True:\n",
" r = requests.get(url+f'&o=5&page={p}') # 排序依暢銷度&跳到p頁\n",
" if r.status_code == 200:\n",
" soup = BeautifulSoup(r.text)\n",
" print(p, end='.')\n",
" p += 1\n",
" books = soup.find_all(class_ = 'item')\n",
" for book in books:\n",
" book_info = book.find(class_ = 'info')\n",
" if book_info:\n",
" df.loc[len(df)+1] = None\n",
" df.iloc[-1]['書名'] = book.find('h4').text\n",
" df.iloc[-1]['作者'] = book_info.text.split(',')[0]\n",
" df.iloc[-1]['出版日期'] = book_info.text.split(',')[-1].split(':')[-1]\n",
" df.iloc[-1]['內容介紹'] = book.find(class_ = 'txt_cont').text\n",
" df.iloc[-1]['網址'] = book.find('a').get('href')\n",
" if len(df) < 100 or '共有<em>100</em>本' in r.text: # 分類少於100本或等於100本\n",
" break\n",
" elif r.status_code == 404: # 超過頁數\n",
" break\n",
" else:\n",
" print('(暫停一分鐘)', end='.')\n",
" sleep(60)\n",
" df.to_csv('drive/My Drive/博客來-中文書/'+filename+'.csv')\n",
" print('✅')\n"
]
}
],
"metadata": {
"colab": {
"provenance": [],
"include_colab_link": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment