爲了有趣咱們今天就主要去爬取如下MM的圖片,並將其按名保存在本地。要爬取的網站爲: 大秀臺模特網 html
1. 分析網站python
進入官網後咱們發現有不少分類:正則表達式
而咱們要爬取的模特中的女模內容,點進入以後其網址爲: http://www.daxiutai.com/mote/5.html ,這也將是咱們爬取的入口點,爲了方便,咱們只是爬取其推薦的部分的模特的信息和圖片。
瀏覽器
當咱們點擊其中的一我的物的時候就會進入他們的我的主頁中,裏邊包括我的的詳細信息以及各類圖片。模特的詳細都將從這裏爬取。app
上述的我的主頁中的模特圖片不全,因此模特的圖片將從其照片展現網頁中爬取,而其照片的展現網頁能夠經過點擊任意主頁上的圖片進入,以下圖所示:ide
咱們要實現的效果就是每一個模特一個文件夾,特定模特文件夾下包括一個模特信息說明的txt文檔以及其全部爬取到圖片測試
2. 爬取過程
網站
2.1 爬取各個模特的主頁地址
url
在點擊女性模特頁面中的模特頭像的時候就會進入此模特的主頁之中,而各個模特的主頁中包含模特的主要信息,因此要先在 http://www.daxiutai.com/mote/5.html 中得到每一個模特的主頁地址。spa
其最裏邊的<li>標籤中就包含模特的主頁地址信息,經過藍色選中部分中地址就能夠獲取模特主頁地址,但卻不是圖片的地址,應爲其是被重定向過。
In [93]: url_femal = "http://www.daxiutai.com/mote/5.html" In [94]: request = urllib2.Request(url_femal) In [95]: response = urllib2.urlopen(request) In [96]: content = response.read()
#綠色部分就是獲取到的地址 In [105]: pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S) In [106]: result = re.findall(pattern,content)
In [107]: result[0]
Out[107]: 'http://www.daxiutai.com/mote_profile/13517.html'
# 總共抓取了60條數據 In [108]: len(result) Out[108]: 60
艾,寫網頁的那個傢伙太懶了沒有把女模特和其它的模特區分開來,因此只能把其餘的都抓取下來,並且有重複地址,因此還要去重。
# 去除重複
In [110]: result = list(set(result)) In [111]: len(result) Out[111]: 57
由於上述這些抓取到的地址在訪問的時候會重定向,因此咱們須要一一獲取其重定後的地址,這一階段比較費時間,得等一下子。
#重定位後的地址放在main_url中
In [124]: main_url = [] # 循環獲取重定位後的地址 In [125]: for item in result: ...: res = urllib2.urlopen(item) ...: main_url.append(res.geturl()) ...: print res.geturl()
http://www.daxiutai.com/mote_profile/13523.html http://heijin.daxiutai.com/ http://fuxinyu.daxiutai.com/ http://152nicai.daxiutai.com/ http://lfh0706.daxiutai.com/ http://649629484.daxiutai.com/
........................
上述打印的地址中紅色類型的地址不是重定位後的地址,且是不可訪問的,若是在瀏覽器中輸入此地址會出現以下反應:
因此這樣的地址是須要剔除的,剔除時所依據的特性就是//後邊是否接着www。
In [135]: main = [] In [136]: for item in main_url: ...: mat = re.match(".*?www.*?",item) ...: if not mat: ...: main.append(item) # 剔除以後還有55條數據 In [137]: len(main) Out[137]: 55
2.2 爬取模特的我的信息
模特的我的信息顯示如圖所示:
HTML源碼狀況爲:
粗略提取一個模特的信息:
In [184]: response = urllib2.urlopen(main[10],timeout=5) ...: content = response.read() In [185]: pattern = re.compile(r"<strong>(.*?)</strong>(.+?)<br\s*/>") In [186]: result = re.findall(pattern,content) In [187]: for item in result: ...: print item[0],item[1] 暱稱: 我纔是寶寶 空間地址: <br /><a href="http://babysix.daxiutai.com/">http://babysix.daxiutai.com/</a> 性別 :女 出生年月 :2016-03 籍貫 :天津市 天津市 身高 :166cm 體重 :45kg 三圍 :82 63 88 鞋碼 :38 膚色 :黃色 頭髮顏色 :黑 婚姻情況 :未婚 是否有紋身 :無 紋身何處 : 是否能夠拍內衣廣告 :不能夠
咱們發如今匹配過程當中中文的:符號也被匹配出來了,而這個在匹配過程當中應該去掉。同時空間地址一項的結果明顯混亂,可是爲了避免增長正則表達式的難度,咱們在後續處理中直接用咱們重定向後的地址取代這個地址便可。
由於包含中文符號的狀況多是這樣的:
也會是這樣的:
因此明顯感受到了網頁的做者的慢慢的惡意。。。。。,因此咱們用 (?::)? 來解決這個問題。分組中?:表示匹配但不計入結果,接下來的:是要匹配到的中文冒號,必定要是中文的,分組外邊的?表示這個分組能夠匹配到也能夠匹配不到都行。
In [205]: response = urllib2.urlopen(main[10],timeout=5) In [206]: content = response.read() In [207]: pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>") In [208]: result = re.findall(pattern,content) In [209]: for item in result: ...: print item[0],item[1] ...: 暱稱 我纔是寶寶 空間地址 <br /><a href="http://babysix.daxiutai.com/">http://babysix.daxiutai.com/</a> 性別 女 出生年月 2016-03 籍貫 天津市 天津市 身高 166cm 體重 45kg 三圍 82 63 88 鞋碼 38 膚色 黃色 頭髮顏色 黑 婚姻情況 未婚 是否有紋身 無 紋身何處 : # 這裏仍是有些問題,爲了簡單咱們就再也不更改內容了 是否能夠拍內衣廣告 不能夠
上邊僅僅是獲取一個模特的詳細信息,接下來咱們將獲取全部的模特的信息:
In [90]: result = [] In [90]: for item in main: response = urllib2.urlopen(item,timeout=8) content = response.read() temp = re.findall(pattern,content) result.append(temp)
上述獲取的結果都存儲在result中,可是顯示效果卻很low,爲了好看,咱們用DataFrame存儲。
注意:下邊的代碼若是直接copy到ipython中執行會有錯誤,最好是本身按照代碼層級本身敲入:
for item in main: response = urllib2.urlopen(item,timeout=8) content = response.read() temp = re.findall(pattern,content) line_list = [] for x in temp: line_list.append(list(x))
# 這裏 line_list[1][1] = item line_dict = dict(line_list) result.append(line_dict) frame = DataFrame(result)
效果以下圖所表示(只是截取了前10個信息):
爲了方便,咱們將這個過程寫爲一個python可執行文件,內容以下:
#!/usr/bin/python #! -*- coding:utf-8 -*- import urllib import urllib2 import re import numpy as np import pandas as pd from pandas import DataFrame,Series class ScrapModel: def __init__(self): self.entry_url = "http://www.daxiutai.com/mote/5.html" def get_personal_address(self): try: print "進入主頁中..." request = urllib2.Request(self.entry_url) response = urllib2.urlopen(request,timeout=5) content = response.read() pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S) original_add = re.findall(pattern,content) # 去重複 original_add = list(set(original_add)) redirect_add = [] print "獲取重定向地址中..." for item in original_add: res = urllib2.urlopen(item,timeout=5) url = res.geturl() # 去除不可訪問地址 mat = re.match(r".*?www.*?",url) if not mat: redirect_add.append(url) print url return redirect_add except Exception,e: if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None def get_personal_info(self,redirect_add): if (len(redirect_add) == 0): print "傳入參數長度爲0" return None try: pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>") print "獲取模特信息中..." result = [] for item in redirect_add: response = urllib2.urlopen(item,timeout=8) content = response.read() temp = re.findall(pattern,content) line_list = [] for x in temp: # list(x) 是將匹配到的二元組變換爲二元的list line_list.append(list(x)) print "獲取到 %s 的信息"%line_list[0][1] # 這裏從新設置模特的空間地址 line_list[1][1] = item # 這個作法會將二元list的第一個元素變成字典的類型的key,對應的第二個會變成value line_dict = dict(line_list) result.append(line_dict) # 將結果轉換爲DataFrame類型 frame = DataFrame(result) print frame return frame except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None spider = ScrapModel() redirect_add = spider.get_personal_address() spider.get_personal_info(redirect_add)
2.3 爬取模特的圖片
在模特的我的主頁中點擊相冊就會進入相冊界面,其地址格式爲: 我的主頁/album.html
而點擊其中的任意一個相冊就會進入其圖片展現頁面,而咱們的圖片也將從這裏抓取
因此接下來咱們要獲取每個相冊的地址,咱們從每一個模特的相冊集頁面中進入,也就是地址格式爲: 我的主頁地址/album.html 的形式:
In [226]: url = "http://yiyingxing.daxiutai.com/album.html" In [227]: response =urllib2.urlopen(urllib2.Request(url)) In [228]: content = response.read() In [229]: pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>") In [230]: albums = re.findall(pattern,content) In [231]: albums Out[231]: ['http://yiyingxing.daxiutai.com/photo/14422.html', 'http://yiyingxing.daxiutai.com/photo/14421.html']
接下來咱們獲取全部模特的相冊地址
# model_info就是前邊一節中get_personal_info返回的結果
def get_albums_address(modle_info): albums_addr = {} try: redirect_add = modle_info.index.tolist() pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>") for item in redirect_add: response = urllib2.urlopen(item + "album.html",timeout=10) content = response.read() albums = re.findall(pattern,content) print "the albums is:",albums albums_addr[item] = albums return albums_addr except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None
獲取到的地址放在字典類型中,其中的每一項的key值是模特的我的主頁,value就是相冊地址構成的列表。
獲取到了相冊地址以後就該進入每個相冊中獲取其圖片,可是有的時候其相冊頁面中的圖片就是原圖,像這樣的:
但有的時候卻又是縮略圖,是這樣的:
實際上去掉圖片名中 _thumb 就會是原圖地址,因此這兩種都按照一種形式抓取,而後去掉縮略圖中的 _thumb:
def get_album_photos(address): print "獲取一個新模特的圖片中..." photos = [] try: pattern = re.compile(r"<p><a.*?rel=\"(.*?)\".*?/a></p>") for item in address: response = urllib2.urlopen(item,timeout=10) content = response.read() temp = re.findall(pattern,content) if temp: print "得到了MM的%d張照片",len(temp) photos = photos + temp if not photos: print "這傢伙太懶了,什麼圖片都沒有留下.." return None return photos except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None
用獲取到的模特相冊地址測試調用:
In [35]: get_album_photos(albums_addr["http://timey.daxiutai.com/"]) 獲取一個新模特的圖片中... 得到了MM的%d張照片 8 得到了MM的%d張照片 11 得到了MM的%d張照片 13 Out[35]: ['http://www.daxiutai.com/uploadfiles/user/i191156228/20160513/cf7a25fcbde925cc1aec6654da47ebe4.jpg', 'http://www.daxiutai.com/uploadfiles/user/i191156228/20160513/35bbdb12829a7ca080beb3804e541da7.jpg',
獲取全部的圖片,並將放入字典類型中
def get_all_photos(albums_addr): photos = {} for key in albums_addr: temp = get_album_photos(albums_addr[key]) if temp: photos[key] = temp return photos
2.4 信息保存
模特的圖片和我的信息已經有了,接下來咱們就將其保存在本地。
def save_one_info(self,info,photos): dir_name = info[" 暱稱"] exists = os.path.exists(dir_name) if not exists: print "建立模特文件夾:"+dir_name os.makedirs(dir_name) print "保存模特信息中: "+dir_name one.to_csv(dir_name+"/"+dir_name+".txt",sep=":") for photo in photos: photo = re.sub("_thumb","",photo) file_name = dir_name+"/"+re.split("/",photo)[-1] print "正在保存圖片: "+file_name res = urllib.urlopen(photo) data = res.read() f = open(file_name,"wb") f.write(data) f.close()
測試一我的的保存:
save_one_info(modle_info.ix["http://zaokai456789.daxiutai.com/"],all["http://zaokai456789.daxiutai.com/"])
保存後的結果:
好了,接下來咱們將保存全部人的圖片以及信息:
def save_all_info(modle_info,modles_photos): for item in modles_photos: save_one_info(modle_info.ix[item],modles_photos[item])
3. 完整的爬取過程
python 入手不久,歡迎大神莫噴
#!/usr/bin/python #! -*- coding:utf-8 -*- import os import urllib import urllib2 import re import numpy as np import pandas as pd from pandas import DataFrame,Series class ScrapModel: def __init__(self): self.entry_url = "http://www.daxiutai.com/mote/5.html" self.modle_info = DataFrame() self.albums_addr = {} def get_personal_address(self): try: print "進入主頁中..." request = urllib2.Request(self.entry_url) response = urllib2.urlopen(request,timeout=5) content = response.read() pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S) original_add = re.findall(pattern,content) # 去重複 original_add = list(set(original_add)) redirect_add = [] print "獲取重定向地址中..." for item in original_add: res = urllib2.urlopen(item,timeout=5) url = res.geturl() # 去除不可訪問地址 mat = re.match(r".*?www.*?",url) if not mat: redirect_add.append(url) print url return redirect_add except Exception,e: if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None def get_personal_info(self,redirect_add): if (len(redirect_add) == 0): print "傳入參數長度爲0" return None try: pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>") print "獲取模特信息中..." result = [] for item in redirect_add: response = urllib2.urlopen(item,timeout=10) content = response.read() temp = re.findall(pattern,content) line_list = [] for x in temp: # list(x) 是將匹配到的二元組變換爲二元的list line_list.append(list(x)) print "獲取到 %s 的信息"%line_list[0][1] # 這裏從新設置模特的空間地址 line_list[1][1] = item # 這個作法會將二元list的第一個元素變成字典的類型的key,對應的第二個會變成value line_dict = dict(line_list) result.append(line_dict) # 將結果轉換爲DataFrame類型 self.modle_info = DataFrame(result) self.modle_info = self.modle_info.set_index("空間地址") print self.modle_info return self.modle_info except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None #獲取每一個模特的每一個相冊的地址,每一個模特都會有一個默認相冊地址,可是裏邊可能沒有圖片 def get_albums_address(self): try: redirect_add = self.modle_info.index.tolist() pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>") for item in redirect_add: response = urllib2.urlopen(item + "album.html",timeout=10) content = response.read() albums = re.findall(pattern,content) print "the albums is:",albums self.albums_addr[item] = albums return self.albums_addr except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None # 獲取一個模特的全部圖片地址 def get_album_photos(self,address): print "獲取一個新模特的圖片中..." photos = [] try: pattern = re.compile(r"<p><a.*?rel=\"(.*?)\".*?/a></p>") for item in address: response = urllib2.urlopen(item,timeout=10) content = response.read() temp = re.findall(pattern,content) if temp: print "得到了MM的%d張照片",len(temp) photos = photos + temp if not photos: print "這傢伙太懶了,什麼圖片都沒有留下.." return None return photos except Exception,e: print Exception,e if hasattr(e,"reason"): print u"鏈接失敗,緣由:",e.reason if hasattr(e,"code"): print "code:",e.code return None # 獲取全部模特的圖片地址 def get_all_photos(self,albums_addr): photos = {} for key in albums_addr: temp = self.get_album_photos(albums_addr[key]) if temp: photos[key] = temp return photos # 保存一個模特的信息 def save_one_info(self,info,photos): dir_name = info[" 暱稱"] exists = os.path.exists(dir_name) if not exists: print "建立模特文件夾:"+dir_name os.makedirs(dir_name) print "保存模特信息中: "+dir_name info.to_csv(dir_name+"/"+dir_name+".txt",sep=":") for photo in photos: photo = re.sub("_thumb","",photo) file_name = dir_name+"/"+re.split("/",photo)[-1] print "正在保存圖片: "+file_name res = urllib.urlopen(photo) data = res.read() f = open(file_name,"wb") f.write(data) f.close() # 保存全部模特的信息 def save_all_info(self,modle_info,modles_photos): for item in modles_photos: self.save_one_info(modle_info.ix[item],modles_photos[item]) spider = ScrapModel() redirect_add = spider.get_personal_address() frame = spider.get_personal_info(redirect_add) albums = spider.get_albums_address() all_photos = spider.get_all_photos(albums) spider.save_all_info(frame,all_photos)