經過前面的一些基礎學習,我們大致知道了如何爬取並解析一個網頁中的信息,這里我們來做一個更有意思的事情,爬取MM圖片並保存。網址為https://mm.taobao.com/json/request_top_list.htm。這個網址有很多頁,通過在網址后添加?page=頁碼來進入指定的頁。
為了爬取模特的圖片,我們首先要找到各個模特自己的頁面。通過查看網頁源碼,我們可以發現,模特各自的頁面的特點如下:
我們可以通過查找class屬性為lady-name的標簽,然后取其href屬性來獲取各個模特各自的頁面地址。
1 html = urlopen(url) 2 bs = BeautifulSoup(html.read().decode('gbk'),"html.parser") 3 girls = bs.findAll("a",{"class":"lady-name"}) 4 for item in girls: 5 linkurl = item.get('href')
繼續分析模特各自的頁面的特點,模特頁面打開后的頁面布局如下:
在這個頁面中我們要提取的是模特的個性域名,這個域名打開后,里面就有模特的圖片了。那么我們的關鍵問題就是如何提取這個域名。按我們之前的學習,我們會去查找這個標簽,但是我們打開網頁源碼會發現網頁源碼里面並沒有包含這個信息。這是因為這一部分的信息是用JS動態生成的。那么這種情況下我們怎么辦呢?
答案是使用selenium和PhantomJS,相關的概念可以自行百度。簡而言之,PhantomJS是一個無界面的瀏覽器,而selenium是一個測試瀏覽器的工具,結合這2者,我們就可以解析動態的頁面了。
獲取模特的個性域名的代碼如下:
1 def getUrls(url): 2 driver= webdriver.PhantomJS() 3 html = urlopen(url) 4 bs = BeautifulSoup(html.read().decode('gbk'),"html.parser") 5 girls = bs.findAll("a",{"class":"lady-name"}) 6 namewithurl = {} 7 for item in girls: 8 linkurl = item.get('href') 9 driver.get("https:"+linkurl) 10 bs1 = BeautifulSoup(driver.page_source,"html.parser") 11 links = bs1.find("div",{"class":"mm-p-info mm-p-domain-info"}) 12 if links is not None: 13 links = links.li.span.get_text() 14 namewithurl[item.get_text()] = links 15 print(links) 16 return namewithurl
在這里,我們使用PhantomJs去加載動態的頁面,然后用BeautifulSoup去規則化加載后的頁面,接下來的工作就與普通的網頁相同了。
接下來分析模特的個人主頁的特點,直觀上是這樣的頁面:
分析源碼后我們會發現,模特的圖片地址可以這樣獲取:
1 html = urlopen(personurl) 2 bs = BeautifulSoup(html.read().decode('gbk'),"html.parser") 3 contents = bs.find("div",{"class":"mm-aixiu-content"}) 4 imgs = contents.findAll("img",{"src":re.compile(r'//img\.alicdn\.com/.*\.jpg')})
如此我們就能獲取模特的個人域名地址中的圖片了,接下來的問題就是如何保存圖片了。
我們可以用urllib中的urlretrieve函數來完成保存的工作。
用法為urlretrieve(imgurl, savepath)
再加入多線程等代碼,完整的爬蟲代碼為:
1 #coding = utf-8
2 from urllib.request import urlopen 3 from urllib.request import urlretrieve 4 from urllib.error import HTTPError 5 from selenium import webdriver 6 from selenium.webdriver.common.by import By 7 from bs4 import BeautifulSoup 8 from multiprocessing.dummy import Pool as ThreadPool 9 import sys,os 10 import re 11
12 savepath=r".\save"
13
14 def mkdir(path): 15 if os.path.exists(path): 16 return
17 os.mkdir(path) 18
19 def getUrls(url): 20 driver= webdriver.PhantomJS() 21 html = urlopen(url) 22 bs = BeautifulSoup(html.read().decode('gbk'),"html.parser") 23 girls = bs.findAll("a",{"class":"lady-name"}) 24 namewithurl = {} 25 for item in girls: 26 linkurl = item.get('href') 27 driver.get("https:"+linkurl) 28 bs1 = BeautifulSoup(driver.page_source,"html.parser") 29 links = bs1.find("div",{"class":"mm-p-info mm-p-domain-info"}) 30 if links is not None: 31 links = links.li.span.get_text() 32 namewithurl[item.get_text()] = links 33 print(links) 34 return namewithurl 35
36 def getImgs(parms): 37 personname = parms[0] 38 personurl = "https:"+parms[1] 39 html = urlopen(personurl) 40 bs = BeautifulSoup(html.read().decode('gbk'),"html.parser") 41 contents = bs.find("div",{"class":"mm-aixiu-content"}) 42 imgs = contents.findAll("img",{"src":re.compile(r'//img\.alicdn\.com/.*\.jpg')}) 43 savefilename = os.path.join(savepath,personname) 44 mkdir(savefilename) 45 print("img num :",len(imgs)) 46 cnt = 0 47 for img in imgs: 48 try: 49 urlretrieve(url = "https:"+img.get("src"),filename =os.path.join(savefilename,str(cnt)+".jpg")) 50 cnt+=1
51 except HTTPError as e: 52 continue
53
54 if __name__ == "__main__": 55 mkdir(savepath) 56 pagenum = 10
57 for i in range(1,pagenum): 58 urls = getUrls("https://mm.taobao.com/json/request_top_list.htm"+"?page="+str(i)) 59 pool = ThreadPool(4) 60 pool.map(getImgs,urls.items()) 61 pool.close() 62 pool.join() 63 # for (k,v) in urls.items():
64 # getImgs((k,v))
代碼下載地址:
https://github.com/HaoLiuHust/Spider
運行結果如下: