python爬取豆瓣top250資訊並存入資料庫中 | sqlite3
阿新 • • 發佈:2022-05-30
- 注:本文承接上文:初學python爬蟲,爬取“豆瓣電影 Top 250”相關資訊,並下載電影封面
- 效果:
程式碼:
# -*- coding: utf-8 -*- # @Time : 2021/9/4 17:32 # @Author : xinyang # @File : spider.py # @Software: PyCharm from bs4 import BeautifulSoup import re import urllib import xlwt # 與生成Excel表格相關 import sqlite3 def main(): baseurl = "https://movie.douban.com/top250?start=" datalist = getData(baseurl) # savepath = "豆瓣電影top250.xls" # 預設與此.py檔案在同一個目錄下 dbpath = "movie.db" # saveData(datalist, savepath) saveData2DB(datalist, dbpath) # askURl("https://movie.douban.com/top250?start=") # 全域性變數 findLink = re.compile(r'<a href="(.*?)">') # 建立正則表示式物件,表示規則(字串的模式) # .* 表示許多的各種的字元, ? 表示 這樣的字元"有"或者“沒有”(0次或者1次) # 例子:<a href="https://movie.douban.com/subject/1291546/">或者<a href=" 將沒有連結的包含在內(考慮意外情況) # 影片圖片 findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S) # re.S表示忽略換行符 因為 . 不包含換行符,加上re.S就可以把 .的概念“匹配”到任何字元 # 影片片名 findTitle = re.compile(r'<span class="title">(.*)</span>') # 影片評分 findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>') # 找到評價人數 findJudge = re.compile(r'<span>(\d*)人評價</span>') # \d* 表示0到多個數字 # 不能寫成(r'<span>1893209人評價</span>') 因為可能因為span標籤不止一個而匹配不成功 # 找到概況 findInq = re.compile(r'<span class="inq">(.*)</span>') # 找到影片的相關內容 findBd = re.compile(r'<p class="">(.*?)</p>', re.S) # 忽視(.所不包含的)換行符 # 此處的?不可省略, 因為<\p>可能不止一個 # 注:省略?之後在”肖申克的救贖“電影中輸出的結果:'導演: 弗蘭克·德拉邦特 Frank Darabont\xa0\xa0\xa0主演: 蒂姆·羅賓斯 Tim Robbins ... 1994\xa0 \xa0美國\xa0 \xa0犯罪 劇情\n < p>\n<div class="star">\n<span class="rating5-t">< span>\n<span class="rating_num" property="v:average">9.7< span>\n<span content="10.0" property="v:best">< span>\n<span>2310473人評價< span>\n< div>\n<p class="quote">\n<span class="inq">希望讓人自由。< span>' # 爬取網頁 def getData(baseurl): datalist = [] for i in range(0, 10): # 呼叫獲取頁面資訊的函式,10次 url = baseurl + str(i * 25) html = askURl(url).replace(u'\xa0', '') # 儲存獲取到的網頁原始碼 # html = html.replace('\xa0', ' ') # 2.逐一解析資料 soup = BeautifulSoup(html, "html.parser") # 指定Beautiful的解析器為“html.parser”,類似的還有BeautifulSoup(markup,"lxml")BeautifulSoup(markup, "lxml-xml") BeautifulSoup(markup,"xml")等等很多種 # 注:解析器負責把 HTML 解析成相關的物件,而 BeautifulSoup 負責操作資料(增刪改查)。“html.parser” 是 Python 內建的解析器 for item in soup.find_all('div', class_="item"): # 查詢符合要求的字串,形成列表(注:class是一個類別/屬性,需要加下劃線,否則會報錯) # print(item)#測試檢視電影item data = [] item = str(item) # 影片詳情的連結 link = re.findall(findLink, item)[0] # re庫用來通過正則表示式查詢指定的字串 data.append(link) # 新增連結 imgSrc = re.findall(findImgSrc, item)[0] data.append(imgSrc) # 新增圖片 titles = re.findall(findTitle, item) # 片名可能只有一箇中文名,沒有外國名 if (len(titles) == 2): ctitle = titles[0] # 新增中文名 data.append(ctitle) otitle = titles[1].replace("/", "") # 去掉無關的符號 data.append(otitle) # 新增外國名 else: data.append(titles[0]) data.append(' ') # 外國名字留空 rating = re.findall(findRating, item)[0] data.append(rating) # 新增評分 judgeNum = re.findall(findJudge, item)[0] data.append(judgeNum) # 新增評價人數 inq = re.findall(findInq, item) if len(inq) != 0: inq = inq[0].replace("。", "") # 去掉句號 data.append(inq) # 新增概述 else: data.append(" ") # 留空 bd = re.findall(findBd, item)[0] bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 去掉<br/> bd = re.sub('/', " ", bd) # 替換/ data.append(bd.strip()) # 去掉前後的空格 datalist.append(data) # print(datalist) return datalist def askURl(url): # 得到指定一個URL的網頁內容 head = { "User-Agent": "Mozilla/5.0(Windows NT 10.0;Win64;x64) AppleWebKit/537.36(KHTML, likeGecko) Chrome / 89.0.4389.90Safari / 537.36" } request = urllib.request.Request(url, headers=head) try: response = urllib.request.urlopen(request) html = response.read().decode("utf-8").replace(' ','') # html.decode().replace(' ', '').encode(encoding='utf-8') # print(html) except urllib.error.URLError as e: if hasattr(e, "code"): print(e.code) if hasattr(e, "reason"): print(e.reason) return html # 儲存資料 def saveData(datalist, savepath): print("save....") book = xlwt.Workbook(encoding="utf-8", style_compression=0) # 建立workbook物件 style_compression=0表示樣式壓縮的效果 sheet = book.add_sheet('豆瓣電影Top250', cell_overwrite_ok=True) # 建立工作表 cell_overwrite_ok=True表示覆蓋之前的內容 col = ("電影詳情連結", "圖片連結", "影片中文名", "影片外國名", "評分", "評價數", "概況", "相關資訊") for i in range(0, 8): sheet.write(0, i, col[i]) # 列名 for i in range(0, 250): print("第%d條" % (i + 1)) data = datalist[i] for j in range(0, 8): sheet.write(i + 1, j, data[j]) # 資料 book.save(savepath) # 儲存 def saveData2DB(datalist, dbpath): init_db(dbpath) conn = sqlite3.connect(dbpath) cur = conn.cursor() for data in datalist: for index in range(len(data)): if index ==4 or index ==5: continue data[index] = '"' + data[index] + '"' sql = ''' insert into movie250( info_link,pic_link,cname,ename,score,rated,introduction,info) values(%s)''' % ",".join(data) cur.execute(sql) conn.commit() cur.close() conn.close() def init_db(dbpath): sql = ''' create table movie250 ( id integer primary key autoincrement, info_link text, pic_link text, cname varchar, ename varchar , score numeric , rated numeric , introduction text, info text ) ''' # 建立資料表 # 最後一個不需加逗號 conn = sqlite3.connect(dbpath) # 連線資料庫(如果資料庫不存在會自動建立資料庫) cursor = conn.cursor() cursor.execute(sql) # 執行sql語句;execute() 將只執行一條單獨的 SQL 語句 conn.commit() # 這個方法提交當前事務。 conn.close() # 關閉資料庫連線。 if __name__ == "__main__": main() # init_db("movietest.db") print("爬取完畢!")
遇到的問題:
1.關於資料庫表格中出現:NBSP
原本的程式碼:
html = response.read().decode("utf-8")
修改之後:
html = response.read().decode("utf-8").replace(' ','')
參考:python爬蟲 爬取內容的時候  空格內容變成問號‘?’ - 可樂爆炸的回答 - 知乎 https://www.zhihu.com/question/35945782/answer/382589149
2. 為什麼HTML欄位中會出現&NBSP?
- 在html程式碼中每輸入一個轉義字元 就表示一個空格,輸入十個 ,頁面中就顯示10個空格位置。
- 而在html程式碼中輸入空格,不管輸入多少個空格,最終在頁面中顯示的空格位置只有一個。
舉例:hmtl程式碼中,在兩個字之間輸入十個空格與輸入十個轉義字元 的效果對比。
3.java.io.IOException: 不能刪除資料庫檔案
-
方法一:首先在右側的資料庫中將其“remove”,然後再在檔案目錄中將其刪除;
-
方法二:
啟動工作管理員,結束pycharm程序下的外掛(結束任務)
參考:java.io.IOException: 不能刪除資料庫檔案
4. 關於decode和encode的區別
- 首先要搞清楚,字串在Python內部的表示是unicode編碼,因此,在做編碼轉換時,通常需要以unicode作為中間編碼;
- (即先將其他編碼的字串解碼(decode)成unicode,再從unicode編碼(encode)成另一種編碼。)
- decode的作用:將其他編碼的字串轉換成unicode編碼;
- 如str1.decode('gb2312'),表示將gb2312編碼的字串str1轉換成unicode編碼。
- encode的作用:將unicode編碼轉換成其他編碼的字串;
- 如str2.encode('gb2312'),表示將unicode編碼的字串str2轉換成gb2312編碼。
總結:想要將其他的編碼轉換成utf-8必須先將其解碼成unicode然後重新編碼成utf-8,它是以unicode為轉換媒介的