目標網址:https://movie.douban.com/top250?start=0&filter=javascript
start=後面的數字從0,25,50一直到225,共10頁,每頁25條信息html
頁面截圖:java
由此主頁面獲取各個電影的連接,而後分別跳轉至對應對應的連接爬取信息。web
主頁面源碼:正則表達式
<li> <div class="item"> <div class="pic"> <em class="">1</em> <a href="https://movie.douban.com/subject/1292052/"> <img width="100" alt="肖申克的救贖" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class=""> </a> </div> <div class="info"> <div class="hd"> <a href="https://movie.douban.com/subject/1292052/" class=""> <span class="title">肖申克的救贖</span> <span class="title"> / The Shawshank Redemption</span> <span class="other"> / 月黑高飛(港) / 刺激1995(臺)</span> </a> <span class="playable">[可播放]</span> </div> <div class="bd"> <p class=""> 導演: 弗蘭克·德拉邦特 Frank Darabont 主演: 蒂姆·羅賓斯 Tim Robbins /...<br> 1994 / 美國 / 犯罪 劇情 </p> <div class="star"> <span class="rating5-t"></span> <span class="rating_num" property="v:average">9.7</span> <span property="v:best" content="10.0"></span> <span>2009428人評價</span> </div> <p class="quote"> <span class="inq">但願讓人自由。</span> </p> </div> </div> </div> </li>
能夠看到,連接藏在<div class="hd">中。shell
而後咱們跳轉到第一個電影(肖申克的救贖)頁面,查看待爬取信息所在的位置。json
片名:瀏覽器
<h1> <span property="v:itemreviewed">肖申克的救贖 The Shawshank Redemption</span> <span class="year">(1994)</span> </h1>
其餘信息:網絡
<div id="info"> <span ><span class='pl'>導演</span>: <span class='attrs'><a href="/celebrity/1047973/" rel="v:directedBy">弗蘭克·德拉邦特</a></span></span><br/> <span ><span class='pl'>編劇</span>: <span class='attrs'><a href="/celebrity/1047973/">弗蘭克·德拉邦特</a> / <a href="/celebrity/1049547/">斯蒂芬·金</a></span></span><br/> <span class="actor"><span class='pl'>主演</span>: <span class='attrs'><a href="/celebrity/1054521/" rel="v:starring">蒂姆·羅賓斯</a> / <a href="/celebrity/1054534/" rel="v:starring">摩根·弗里曼</a> / <a href="/celebrity/1041179/" rel="v:starring">鮑勃·岡頓</a> / <a href="/celebrity/1000095/" rel="v:starring">威廉姆·賽德勒</a> / <a href="/celebrity/1013817/" rel="v:starring">克蘭西·布朗</a> / <a href="/celebrity/1010612/" rel="v:starring">吉爾·貝羅斯</a> / <a href="/celebrity/1054892/" rel="v:starring">馬克·羅斯頓</a> / <a href="/celebrity/1027897/" rel="v:starring">詹姆斯·惠特摩</a> / <a href="/celebrity/1087302/" rel="v:starring">傑弗裏·德曼</a> / <a href="/celebrity/1074035/" rel="v:starring">拉里·布蘭登伯格</a> / <a href="/celebrity/1099030/" rel="v:starring">尼爾·吉恩託利</a> / <a href="/celebrity/1343305/" rel="v:starring">布賴恩·利比</a> / <a href="/celebrity/1048222/" rel="v:starring">大衛·普羅瓦爾</a> / <a href="/celebrity/1343306/" rel="v:starring">約瑟夫·勞格諾</a> / <a href="/celebrity/1315528/" rel="v:starring">祖德·塞克利拉</a> / <a href="/celebrity/1014040/" rel="v:starring">保羅·麥克蘭尼</a> / <a href="/celebrity/1390795/" rel="v:starring">芮妮·布萊恩</a> / <a href="/celebrity/1083603/" rel="v:starring">阿方索·弗里曼</a> / <a href="/celebrity/1330490/" rel="v:starring">V·J·福斯特</a> / <a href="/celebrity/1000635/" rel="v:starring">弗蘭克·梅德拉諾</a> / <a href="/celebrity/1390797/" rel="v:starring">馬克·邁爾斯</a> / <a href="/celebrity/1150160/" rel="v:starring">尼爾·薩默斯</a> / <a href="/celebrity/1048233/" rel="v:starring">耐德·巴拉米</a> / <a href="/celebrity/1000721/" rel="v:starring">布賴恩·戴拉特</a> / <a href="/celebrity/1333685/" rel="v:starring">唐·麥克馬納斯</a></span></span><br/> <span class="pl">類型:</span> <span property="v:genre">劇情</span> / <span property="v:genre">犯罪</span><br/> <span class="pl">製片國家/地區:</span> 美國<br/> <span class="pl">語言:</span> 英語<br/> <span class="pl">上映日期:</span> <span property="v:initialReleaseDate" content="1994-09-10(多倫多電影節)">1994-09-10(多倫多電影節)</span> / <span property="v:initialReleaseDate" content="1994-10-14(美國)">1994-10-14(美國)</span><br/> <span class="pl">片長:</span> <span property="v:runtime" content="142">142分鐘</span><br/> <span class="pl">又名:</span> 月黑高飛(港) / 刺激1995(臺) / 地獄諾言 / 鐵窗歲月 / 消香克的救贖<br/> <span class="pl">IMDb連接:</span> <a href="https://www.imdb.com/title/tt0111161" target="_blank" rel="nofollow">tt0111161</a><br> </div>
能夠看到,該部份內容中包含了導演、編劇、主演、類型、製片國家/地區、語言、上映日期、片長、又名這些信息,它們以分隔符<br/>進行分隔,下面咱們將經過正則表達式進行提取。app
<div class="ratings-on-weight"> <div class="item"> <span class="stars5 starstop" title="力薦"> 5星 </span> <div class="power" style="width:64px"></div> <span class="rating_per">85.1%</span> <br /> </div> <div class="item"> <span class="stars4 starstop" title="推薦"> 4星 </span> <div class="power" style="width:10px"></div> <span class="rating_per">13.4%</span> <br /> </div> <div class="item"> <span class="stars3 starstop" title="還行"> 3星 </span> <div class="power" style="width:0px"></div> <span class="rating_per">1.3%</span> <br /> </div> <div class="item"> <span class="stars2 starstop" title="較差"> 2星 </span> <div class="power" style="width:0px"></div> <span class="rating_per">0.1%</span> <br /> </div> <div class="item"> <span class="stars1 starstop" title="不好"> 1星 </span> <div class="power" style="width:0px"></div> <span class="rating_per">0.1%</span> <br /> </div> </div>
這部分源碼包含了評分5星至1星所佔的百分數比例。
<div class="related-info" style="margin-bottom:-10px;"> <a name="intro"></a> <h2> <i class="">肖申克的救贖的劇情簡介</i> · · · · · · </h2> <div class="indent" id="link-report"> <span class="short"> <span property="v:summary"> 20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名爲肖申克的監獄內,但願彷佛虛無縹緲,終身監禁的懲罰無疑註定了安迪接下來灰暗絕望的人生。未過多久,安迪嘗試接近囚犯中很有聲望的瑞德(摩根·弗里曼 Morgan Freeman 飾),請求對方幫本身搞來小錘子。以此爲契機,二人逐漸熟稔,安迪也彷彿在魚龍混雜、罪惡橫生、黑白混淆的牢獄中找到屬於本身的求生之道。他利用自身的專業知識,幫助監獄管理層逃稅、洗黑錢,同時憑藉與瑞德的交往在犯人中間也漸漸受到禮遇。表面看來,他已如瑞德那樣對那堵高牆從憎恨轉變爲處之泰然,可是對自由的渴望仍促使他朝着心中的但願和目標前進。而關於其罪行的真相,彷佛更使這一切朝前推動了一步…… <br /> 本片根據著名做家斯蒂芬·金(Stephen Edwin King)的... </span> <a href="javascript:void(0)" class="j a_show_full">(展開所有)</a> </span> <span class="all hidden"> 20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名爲肖申克的監獄內,但願彷佛虛無縹緲,終身監禁的懲罰無疑註定了安迪接下來灰暗絕望的人生。未過多久,安迪嘗試接近囚犯中很有聲望的瑞德(摩根·弗里曼 Morgan Freeman 飾),請求對方幫本身搞來小錘子。以此爲契機,二人逐漸熟稔,安迪也彷彿在魚龍混雜、罪惡橫生、黑白混淆的牢獄中找到屬於本身的求生之道。他利用自身的專業知識,幫助監獄管理層逃稅、洗黑錢,同時憑藉與瑞德的交往在犯人中間也漸漸受到禮遇。表面看來,他已如瑞德那樣對那堵高牆從憎恨轉變爲處之泰然,可是對自由的渴望仍促使他朝着心中的但願和目標前進。而關於其罪行的真相,彷佛更使這一切朝前推動了一步…… <br /> 本片根據著名做家斯蒂芬·金(Stephen Edwin King)的原著改編。 </span> <span class="pl"><a href="https://movie.douban.com/help/movie#t0-qs">©豆瓣</a></span> </div> </div>
在影片簡介較長時,所有信息在class屬性爲"all hidden"的span中,而簡介較短時,不存在這一標籤,property屬性爲"x:summary"的span中就已包含了所有文本。
from urllib.request import urlopen, Request from bs4 import BeautifulSoup import re import numpy as np import pandas as pd import time #設置請求頭 headers = {'User-Agent':'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'} def getLinks(articleUrl): """經過頁面獲取各個電影的連接""" req = Request(url=articleUrl, headers=headers) html = urlopen(req) bsObj = BeautifulSoup(html) links = bsObj.findAll("div", {"class": "hd"}) return [link.a.attrs["href"] for link in links] #目標連接 head = "https://movie.douban.com/top250?start=" pages = [head + str(num) + "&filter=" for num in np.arange(0,250,25)] links = [] for page in pages: #拼接全部連接,共250條 links += getLinks(page) def Merge(dict1, dict2): """合併字典""" res = {**dict1, **dict2} return res allInfo = pd.DataFrame() keyList1 = ['導演', '編劇', '主演', '類型', '製片國家/地區', '語言', '上映日期', '片長', '又名'] keyList2 = ['5星', '4星', '3星', '2星', '1星'] def getInfo(articleUrl): """獲取每部電影的詳細信息""" global allInfo req = Request(url=articleUrl, headers=headers) html = urlopen(req) bsObj = BeautifulSoup(html) #獲取基礎信息info1 info1 = bsObj.find("div", {"id": "info"}) info1 = info1.get_text().split('\n')[1:-2] #經過正則表達式刪選信息 #貪婪匹配+?,無匹配生成空字符串|$ pattern1 = re.compile(".+?(?=:)|$") pattern2 = re.compile("(?<=:).+|$") keyList_prepare = [pattern1.findall(i)[0] for i in info1] valueList_prepare = [pattern2.findall(i)[0] for i in info1] valueList1=[None] * len(keyList1) for key in keyList1: if key in keyList_prepare: valueList1[keyList1.index(key)] = valueList_prepare[keyList_prepare.index(key)] dict1 = dict(zip(keyList1,valueList1)) #獲取評分信息info2 info2 = bsObj.find("div", {"class": "ratings-on-weight"}) info2 = info2.findAll("span", {"class", "rating_per"}) valueList2 = [i.get_text() for i in info2] dict2 = dict(zip(keyList2, valueList2)) dictAll = Merge(dict1, dict2) #獲取影片簡介 try: dictAll = Merge(dictAll, {"簡介": bsObj.find("span", {"class": "all hidden"}).get_text().strip()}) except: dictAll = Merge(dictAll, {"簡介": bsObj.find("span", {"property": "v:summary"}).get_text().strip()}) allInfo = allInfo.append(dictAll,ignore_index=True) #返回影片片名 return bsObj.h1.get_text().strip() num = 0 title = [] startTime = time.time() for link in links: title.append(getInfo(link)) num += 1 print("正在爬取第", num, "條信息") endTime = time.time() #片名做爲索引 allInfo.rename(index=dict(zip(range(0,allInfo.shape[0]),title)),inplace=True) #數據框寫入CSV文件 allInfo.to_excel('MovieInfo.xlsx', encoding="utf-8") print("共爬取", allInfo.shape[0], "條信息,用時", endTime-startTime, "秒")
耐心等待後……
打開Excel文件查看:
https://movie.douban.com/subject/1291561/comments?start=0&limit=20&sort=new_score&status=P
start=後面的數字從0開始以20爲公差遞增,咱們爬取0,20,40直到180,即前200條評論。
頁面截圖:
源碼:
<div class="comment"> <h3> <span class="comment-vote"> <span class="votes">3492</span> <input value="82042845" type="hidden"/> <a href="javascript:;" class="j a_show_login" onclick="">有用</a> </span> <span class="comment-info"> <a href="https://www.douban.com/people/oceanheart/" class="">深海的心</a> <span>看過</span> <span class="allstar40 rating" title="推薦"></span> <span class="comment-time " title="2008-12-22 22:28:54"> 2008-12-22 </span> </span> </h3> <p class=""> <span class="short">有那麼那麼經典嗎?仍是我老了?</span> </p> </div>
待爬取信息:
評論用戶、用戶連接、評論內容、評論投票數、評論時間。
import scrapy class TutorialItem(scrapy.Item): author = scrapy.Field()#評論用戶 link = scrapy.Field()#用戶連接 comment = scrapy.Field()#評論內容 vote = scrapy.Field()#評論投票數 time = scrapy.Field()#評論時間
import scrapy from tutorial.items import TutorialItem import numpy as np head = "https://movie.douban.com/subject/1291561/comments?start=" class MySpider(scrapy.Spider): # 設置name name = "douban" # 設定域名 allowed_domains = ["movie.douban.com"] # 填寫爬取地址 start_urls = [head + str(num) + "&limit=20&sort=new_score&status=P" for num in np.arange(0,200,20)] # 編寫爬取方法 def parse(self, response): for line in response.xpath('//div[@class="comment"]'): # 初始化item對象保存爬取的信息 item = TutorialItem() # 這部分是爬取部分,使用xpath的方式選擇信息,具體方法根據網頁結構而定 item['author'] = line.xpath('.//span[@class="comment-info"]/a/text()').extract() item['link'] = line.xpath('.//span[@class="comment-info"]/a/@href').extract() item['comment'] = line.xpath('.//span[@class="short"]/text()').extract() item['vote'] = line.xpath('.//span[@class="comment-vote"]/span[@class="votes"]/text()').extract() item['time'] = line.xpath('.//span[@class="comment-info"]/span[@class="comment-time "]/text()').extract() yield item
仍採用列表存放URL,複習了XPath知識。
設置編碼:
FEED_EXPORT_ENCODING ='utf-8'
修改請求頭:
USER_AGENT = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"
其餘設置保持默認。
另外新建一個py腳本,放在和工程文件夾tutorial相同的目錄下。
import pandas as pd import os import json #切換工做目錄至當前腳本路徑 os.chdir(os.path.split(os.path.realpath(__file__))[0]+'\\tutorial') os.system("rm items.json") os.system("scrapy crawl douban -o items.json") with open('items.json', 'r', encoding='utf-8') as f: data = json.load(f) for i in range(0,len(data)): for k in data[i].keys(): data[i][k] = data[i][k][0].strip() allInfo = pd.DataFrame() allInfo = allInfo.append(data,ignore_index=True) allInfo.to_excel('../commentInfo.xlsx', encoding="utf-8")
執行程序後,在tutorial文件夾下新增items.json文件。
在notepad++中打開查看:
在py腳本文件所在目錄新增commentInfo.xlsx文件,打開查看:
六度分隔(Six Degrees of Separation)理論。簡單地說:「你和任何一個陌生人之間所間隔的人不會超五個,也就是說,最多經過六我的你就可以認識任何一個陌生人。(來自百度百科)
百度百科中有不少詞條,而且相互直接有連接溝通,因此咱們嘗試從某一詞條連接出發,不斷向其餘詞條頁面跳轉,看看是否能在6次以內到達目標詞條。創意來自《Python網絡數據採集》。
這裏以我喜歡的歌手鄧麗君的詞條頁面爲例。
部分源碼:
經過觀察能夠發現,指向其餘詞條的連接都帶有屬性target="_blank",且連接樣式爲相似於/item/%E6%B5%B7%E9%9F%B5的utf-8編碼。
以鄧麗君頁面爲起始頁面,以我喜歡的演員劉亦菲的詞條頁面爲終止頁面。
from urllib.request import urlopen from bs4 import BeautifulSoup import re import random start = "鄧麗君" end = "劉亦菲" def getLinks(articleUrl): html = urlopen("https://baike.baidu.com"+articleUrl) bsObj = BeautifulSoup(html) allLinks = bsObj.findAll("a", {"target": "_blank"}) links = [] for i in range(len(allLinks)): isEntry = re.match("/item/(%[0-9A-F])+.+", allLinks[i].attrs["href"]) text = allLinks[i].get_text().strip() repetition = allLinks[i].attrs["href"] in [link.attrs["href"] for link in links] if isEntry!=None and text!="" and not(repetition): links.append(allLinks[i]) return links def getUTF8(string): UTF8=str(string.encode('utf-8')).upper() pattern = re.compile("(?<=').+(?=')") return re.sub("\\\\X", "%", pattern.findall(UTF8)[0]) startLinks = getLinks("/item/"+getUTF8(start)) flag = 0 #試驗100次 for i in range(0,100): links = startLinks if(flag == 1): break for j in range(0,6): if len(links) > 0: if end in [link.get_text().strip() for link in links]: print("在第",i+1, "輪尋找", "第", j, "次跳轉", "中找到") flag = 1 break ran = random.randint(0, len(links)-1) newArticle = links[ran].attrs["href"] print("第",i+1, "輪尋找", "第", j+1, "次跳轉", links[ran].get_text().strip()) links = getLinks(newArticle) else: print("爬蟲中斷") break if(flag == 0): print("100輪尋找已完成,很遺憾未能找到。請檢查start和end變量是不是百度百科中存在的詞條。")
運行了兩次試驗一下,結果如上所示。
去瀏覽器看一下,確實能夠根據爬蟲給出的路線找到「劉亦菲」。
由於這兩個明星比較有名氣吧,關聯到的詞條比較多,因此通常老是能在100輪尋找中找到,不過這也和運氣有關呢。
能夠修改start和end進行其餘測試,可是須要保證該詞語在百度百科的詞條中存在,不然確定會報錯。