天天看點

Python 爬蟲實作:抓取電影網站資訊并入庫

文章目錄

    • 一.環境搭建
        • 1.下載下傳安裝包
        • 2.修改環境變量
        • 3.安裝依賴子產品
    • 二.代碼開發
    • 三.運作測試
        • 1.建立電影資訊表
        • 2.代碼運作
    • 四.問題排查和修複
        • 1.空白字元報錯
        • 2.請求報錯

一.環境搭建

1.下載下傳安裝包

通路 Python官網下載下傳位址:https://www.python.org/downloads//

下載下傳适合自己系統的安裝包:

Python 爬蟲實作:抓取電影網站資訊并入庫

我用的是 Windows 環境,是以直接下的 exe 包進行安裝。

下載下傳後,輕按兩下下載下傳包,進入 Python 安裝向導,安裝非常簡單,你隻需要使用預設的設定一直點選"下一步"直到安裝完成即可。

2.修改環境變量

Python 爬蟲實作:抓取電影網站資訊并入庫
  • 右鍵點選"計算機",點選"屬性";
  • 然後點選"進階系統設定"-“環境變量”;
  • 選擇"系統變量"視窗下面的 “Path” ,添加 python 安裝路徑;
  • 設定成功以後,在cmd指令行,輸入指令"python",有顯示則說明配置成功。

3.安裝依賴子產品

我們的爬取程式需要安裝的依賴子產品包括 requests,lxml,pymysql ,步驟如下:

  • 進入python安裝目錄下的Scripts目錄,點選位址欄輸入“cmd” 打開指令行工具:
Python 爬蟲實作:抓取電影網站資訊并入庫
  • 在這個路徑下安裝對應的 requests,lxml,pymysql 依賴:
Python 爬蟲實作:抓取電影網站資訊并入庫
  • 需要輸入的指令:
// 安裝requests依賴
pip install requests

// 安裝lxml依賴
pip install lxml

// 安裝pymysql依賴
pip install pymysql
           

二.代碼開發

開發 collectMovies.py

#!/user/bin env python
# 擷取電影天堂詳細資訊
import requests
import time
from lxml import etree
import pymysql
requests.adapters.DEFAULT_RETRIES = 5
# 僞裝浏覽器
HEADERS ={
	'User-Agent':'Mozilla/5.(Windows NT 10.0; WOW64) AppleWebKit/537.3(KHTML, like Gecko) Chrome/63.0.3239.13Safari/537.36',
    'Host':'www.dy2018.com'
}
# 定義全局變量
BASE_DOMAIN = 'https://www.dy2018.com/'
# 擷取首頁網頁資訊并解析
def getUrlText(url,coding):
	s = requests.session()
	#print("擷取首頁網頁資訊并解析:", url)
	respons = s.get(url,headers=HEADERS)
	print("請求URL:", url)
	if(coding=='c'):
		urlText = respons.content.decode('gbk')
		html = etree.HTML(urlText)  # 使用lxml解析網頁
	else:
		urlText = respons.text
		html = etree.HTML(urlText)  # 使用lxml解析網頁
	s.keep_alive = False
	return html

# 擷取電影詳情頁的href,text解析
def getHref(url):
	html = getUrlText(url,'t')
	aHref = html.xpath('//table[@class="tbspan"]//a/@href')
	print("擷取電影詳情頁的href,text解析```")
	htmlAll = map(lambda url:BASE_DOMAIN+url,aHref) # 給每個href補充BASE_DOMAIN
	return htmlAll

# 使用content解析電影詳情頁,并擷取詳細資訊資料
def getPage(url):
	html = getUrlText(url,'c')
	moveInfo = {}  # 定義電影資訊
	mName = html.xpath('//div[@class="title_all"]//h1/text()')[0]
	moveInfo['movie_name'] = mName
	mDiv = html.xpath('//div[@id="Zoom"]')[0]
	mImgSrc = mDiv.xpath('.//img/@src')
	moveInfo['image_path'] = mImgSrc[0]  # 擷取海報src位址
	if len(mImgSrc) >= 2:
		moveInfo['screenshot'] = mImgSrc[1]  # 擷取電影截圖src位址
	mContnent = mDiv.xpath('.//text()')
	def pares_info(info,rule):
		'''
		:param info: 字元串
		:param rule: 替換字串
		:return:  指定字元串替換為空,并剔除左右空格
		'''
		return info.replace(rule,'').strip()
	for index,t in enumerate(mContnent):
		if t.startswith('◎譯  名'):
			name = pares_info(t,'◎譯  名')
			moveInfo['translation']=name
		elif t.startswith('◎片  名'):
			name = pares_info(t,'◎片  名')
			moveInfo['movie_title']=name
		elif t.startswith('◎年  代'):
			name = pares_info(t,'◎年  代')
			moveInfo['movie_age']=name
		elif t.startswith('◎産  地'):
			name = pares_info(t,'◎産  地')
			moveInfo['movie_place']=name
		elif t.startswith('◎類  别'):
			name = pares_info(t,'◎類  别')
			moveInfo['category']=name
		elif t.startswith('◎語  言'):
			name = pares_info(t,'◎語  言')
			moveInfo['language']=name
		elif t.startswith('◎字  幕'):
			name = pares_info(t,'◎字  幕')
			moveInfo['subtitle']=name
		elif t.startswith('◎上映日期'):
			name = pares_info(t,'◎上映日期')
			moveInfo['release_date']=name
		elif t.startswith('◎豆瓣評分'):
			name = pares_info(t,'◎豆瓣評分')
			moveInfo['douban_score']=name
		elif t.startswith('◎片  長'):
			name = pares_info(t,'◎片  長')
			moveInfo['file_length']=name
		elif t.startswith('◎導  演'):
			name = pares_info(t,'◎導  演')
			moveInfo['director']=name
		elif t.startswith('◎編  劇'):
			name = pares_info(t, '◎編  劇')
			writers = [name]
			for i in range(index + 1, len(mContnent)):
				writer = mContnent[i].strip()
				if writer.startswith('◎'):
					break
				writers.append(writer)
			moveInfo['screenwriter'] = writers
		elif t.startswith('◎主  演'):
			name = pares_info(t, '◎主  演')
			actors = [name]
			for i in range(index+1,len(mContnent)):
				actor = mContnent[i].strip()
				if actor.startswith('◎'):
					break
				actors.append(actor)
			moveInfo['stars'] = " ".join(actors)
		elif t.startswith('◎标  簽'):
			name = pares_info(t,'◎标  簽')
			moveInfo['tags']=name
		elif t.startswith('◎簡  介'):
			name = pares_info(t,'◎簡  介')
			profiles = []
			for i in range(index + 1, len(mContnent)):
				profile = mContnent[i].strip()
				if profile.startswith('◎獲獎情況') or '【下載下傳位址】' in profile:
					break
				profiles.append(profile)
			moveInfo['introduction']=" ".join(profiles)
		elif t.startswith('◎獲獎情況'):
			name = pares_info(t,'◎獲獎情況')
			awards = []
			for i in range(index + 1, len(mContnent)):
				award = mContnent[i].strip()
				if '【下載下傳位址】' in award:
					break
				awards.append(award)
			moveInfo['awards']=" ".join(awards)
	moveInfo['movie_url'] = url
	return moveInfo

# 擷取前n頁所有電影的詳情頁href
def spider():
	#連接配接資料庫
	base_url = 'https://www.dy2018.com/html/gndy/dyzz/index_{}.html'
	moves = []
	m = int(input('請輸入您要擷取的開始頁:'))
	n = int(input('請輸入您要擷取的結束頁:'))
	print('即将寫入第{}頁到第{}頁的電影資訊,請稍後...'.format(m, n))
	for i in range(m,n+1):
		print('******* 第{}頁電影 正在寫入 ********'.format(i))
		if i == 1:
			url = "https://www.dy2018.com/html/gndy/dyzz/"
		else:
			url = base_url.format(i)
		moveHref = getHref(url)
		print("休息2s後再進行操作")
		time.sleep(2)
		for index,mhref in enumerate(moveHref):
			print('---- 正在處理第{}部電影----'.format(index+1))
			move = getPage(mhref)
			moves.append(move)
# 将電影資訊寫入資料庫
	db = pymysql.connect(host='127.0.0.1',user='root', password='123456', port=3306, db='你的資料庫名稱')
	table = 'movies'
	i = 1
	for data in moves:
		keys = ', '.join(data.keys())
		values = ', '.join(['%s'] * len(data))
		sql = 'INSERT INTO {table}(id,{keys}) VALUES (null,{values})'.format(table=table, keys=keys, values=values)
		try:
			cursor = db.cursor()
			cursor.execute(sql, tuple(data.values()))
			print('本條資料成功執行!')
			if i%10==0:
   				db.commit()
		except Exception as e:
   			print('将電影資訊寫入資料庫發生異常!',repr(e))
   			db.rollback()
		cursor.close()
		i = i + 1
	db.commit()
	db.close()
	print('寫入資料庫完成!')

if __name__ == '__main__':
	spider()
           

三.運作測試

1.建立電影資訊表

CREATE TABLE `movies` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `movie_name` varchar(255) DEFAULT NULL,
  `image_path` varchar(255) DEFAULT NULL,
  `screenshot` varchar(255) DEFAULT NULL,
  `translation` varchar(255) DEFAULT NULL,
  `movie_title` varchar(255) DEFAULT NULL,
  `movie_age` varchar(50) DEFAULT NULL,
  `movie_place` varchar(50) DEFAULT NULL,
  `category` varchar(100) DEFAULT NULL,
  `language` varchar(100) DEFAULT NULL,
  `subtitle` varchar(100) DEFAULT NULL,
  `release_date` varchar(50) DEFAULT NULL,
  `douban_score` varchar(50) DEFAULT NULL,
  `file_length` varchar(255) DEFAULT NULL,
  `director` varchar(100) DEFAULT NULL,
  `screenwriter` varchar(100) DEFAULT NULL,
  `stars` mediumtext,
  `tags` varchar(255) DEFAULT NULL,
  `introduction` mediumtext,
  `awards` text,
  `movie_url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
           

2.代碼運作

打開 collectMovies.py 所在目錄,輸入指令運作:

python collectMovies.py
           

運作結果如下:

Python 爬蟲實作:抓取電影網站資訊并入庫
Python 爬蟲實作:抓取電影網站資訊并入庫

檢視資料庫表,資料已成功插入:

Python 爬蟲實作:抓取電影網站資訊并入庫

四.問題排查和修複

1.空白字元報錯

第一次使用 Python,不太熟悉它的規則,空格和Tab混用,運作會報如下錯:

unindent does not match any outer indentation level
           

解決方法

下載下傳 Notepad++,選擇 “編輯” – “空白字元操作” – "空格轉 Tab (行首)"即可。

2.請求報錯

修改好格式之後再次運作,反反複複的報請求的錯,報錯資訊主要包括以下内容:

ssl.SSLEOFError: EOF occurred in violation of protocol
······
Max retries exceeded with url
           

解決方法

本來以為是請求設定出了問題,各種百度,還安裝了

pip install incremental

,但是依然沒有奏效。

後來把請求的網址換成百度網就不報錯了,這樣可以定位到是原網址的通路出了問題,更換了采集源路徑,該問題解決。