一個(gè)簡單的爬蟲

功能:爬取目標(biāo)網(wǎng)站全部主要圖片(例子中是美圖錄網(wǎng)站的全部寫真圖片语卤,按人名分類)

本示例使用Python3.5霎槐,需要額外安裝BeautifulSoup 4

BeautifulSoup 4 安裝方法:

Linux:
sudo apt-get install python-bs4

Mac:
sudo easy_install pip
pip install beautifulsoup4

Windows:
下載源碼后场勤,
python setup.py install
或者:
pip install beautifulsoup4

具體安裝方式見:<a >點(diǎn)這里</a>

分析網(wǎng)站結(jié)構(gòu)

目標(biāo)網(wǎng)站<a >“美圖錄”</a>(別問我為什么選這個(gè)網(wǎng)站爹橱。。糯崎。百度上“隨便”找的)

因?yàn)榇蛩阆螺d全部的網(wǎng)頁圖片拓哟,所以從最小的單元開始想许,也就是圖片集(再小就是單一的圖片了,也就可以直接下載了)

先打開首頁断序,隨便點(diǎn)開一個(gè)圖片集流纹,發(fā)現(xiàn)圖片集的地址是這樣的
http://www.meitulu.com/item/7487.html
在圖片集中檢查頁面元素,如下所示

<div class="content">
  <center>
    ![[Ugirls尤果網(wǎng)] U181 陳雅漫 寫真套圖_第1頁/第1張圖](http://upload-images.jianshu.io/upload_images/2475481-8cdfce535296ab31.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  </center>
  <center>
    ![[Ugirls尤果網(wǎng)] U181 陳雅漫 寫真套圖_第1頁/第3張圖](http://upload-images.jianshu.io/upload_images/2475481-43e882deb2d0c0cf.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  </center>
  <center>
    ![[Ugirls尤果網(wǎng)] U181 陳雅漫 寫真套圖_第1頁/第4張圖](http://upload-images.jianshu.io/upload_images/2475481-2d5cb01257ad639e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)    
  </center>
  <center>
    ![[Ugirls尤果網(wǎng)] U181 陳雅漫 寫真套圖_第1頁/第5張圖](http://upload-images.jianshu.io/upload_images/2475481-8e773c5ec770c466.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  </center>
</div>

發(fā)現(xiàn)每一張主要圖片資源鏈接都在center標(biāo)簽中违诗,這樣就可以在這個(gè)頁面上提取圖片鏈接并下載了
繼續(xù)向下漱凝,發(fā)現(xiàn)下圖所示,圖片并不是存放在一個(gè)頁面中的


頁面列表

而檢查這里的html代碼可以看到

<div id="pages">
  <a class="a1" >上一頁</a>
  <span>1</span>
  <a >2</a>
  <a >4</a>
  <a >5</a>
  <a >6</a>
  <a >7</a>
  <a >8</a>
  <a >9</a>
  <a >10</a>
  ".."
  <a >16</a>
  <a class="a1" >下一頁</a>
</div>

這個(gè)頁面列表在class="pages"的div標(biāo)簽中较雕,當(dāng)前頁是用span標(biāo)簽裝飾的碉哑,我們可以通過提取 下一頁 按鈕的鏈接來繼續(xù)下載下一個(gè)頁面的圖片挚币,但是我們?cè)趺粗朗裁磿r(shí)候會(huì)到最后一頁呢?點(diǎn)擊最后一個(gè)頁面的按鈕扣典,這里就是16頁妆毕。再次檢查這一部分的html代碼

<div id="pages">
  <a class="a1" >上一頁</a>
  <a >1</a>
  ".."
  <a >7</a>
  <a >8</a>
  <a >9</a>
  <a >10</a>
  <a >11</a>
  <a >12</a>
  <a >13</a>
  <a >14</a>
  <a >15</a>
  <span>16</span>
  <a class="a1" >下一頁</a>
</div>

從這段代碼中可以看到,下一頁 按鈕的鏈接指向的是16頁贮尖,也就是當(dāng)前頁笛粘,而前面的頁面指向的都是當(dāng)前頁的下一頁。所以我們可以利用這一點(diǎn)來判斷是否到最后一頁湿硝。這樣我們就有了下載一個(gè)完整圖片集的思路了薪前。

下面我們看看如何獲得所有圖片集的鏈接

圖集分類

發(fā)現(xiàn)網(wǎng)站首頁有一個(gè)圖集分類,我們可以認(rèn)為他把網(wǎng)站上所有的資源都放在這里分好類了关斜,隨便點(diǎn)開一個(gè)分類示括,可以看到里面有排列整齊的圖集,檢查html代碼

<div class="boxs">
  <ul class="img">
    <li>
      <a  target="_blank">
        ![[尤蜜薈] 可樂Vicky 蘇梅島旅拍 第二刊 ~[43]](http://upload-images.jianshu.io/upload_images/2475481-1915763ae66ee8ad.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
      </a>
      <p><span>3</span>圖片: 43 張(1600X2400)</p>
      <p>機(jī)構(gòu):
        <a  target="_blank" class="tags">推女神</a>
      </p>
      <p>模特:
        <a  target="_blank" class="tags">可樂Vicky</a>
      </p>
      <p>標(biāo)簽:
        <a  target="_blank" class="tags">極品</a>
        <a  target="_blank" class="tags">女神</a>
        <a  target="_blank" class="tags">清新</a>
        <a  target="_blank" class="tags">清純</a>
        <a  target="_blank" class="tags">唯美</a>
        <a  target="_blank" class="tags">戶外</a>
        <a  target="_blank" class="tags">養(yǎng)眼</a>
      </p>
      <p class="p_title">
        <a  target="_blank">[尤蜜薈] 可樂Vicky 蘇梅島旅拍 第二刊 ~</a>
      </p>
    </li>
    "..."
    <!--為了方便查看痢畜,這里省略了一堆li標(biāo)簽-->
  </ul>
</div>

從這段代碼中可以發(fā)現(xiàn)垛膝,所有的圖集被放在了<div class="boxs">標(biāo)簽中,每個(gè)圖集的信息中包含模特名字丁稀,發(fā)行機(jī)構(gòu)和一系列的標(biāo)簽吼拥。每一個(gè)信息對(duì)應(yīng)一個(gè)鏈接,鏈接中是包含對(duì)應(yīng)信息的圖集的分類頁面线衫,這里我們按照人名分類凿可,所以只要檢索 模特 關(guān)鍵字就可以了。
這段頁面的下方也是一個(gè)頁面列表授账,檢查html元素會(huì)發(fā)現(xiàn)與圖集的列表模式相同枯跑。

另外,對(duì)于某些只有一個(gè)圖集的人來說矗积,他沒有對(duì)應(yīng)的分類頁面全肮,對(duì)于這些人要另外處理

小結(jié)

根據(jù)這些特征敞咧,我們遍歷分類頁面中的所有圖集棘捣,通過字典記錄人名對(duì)應(yīng)的鏈接,如果遇到?jīng)]有分類頁面的人休建,則直接創(chuàng)建文件夾乍恐,下載圖集。這樣我們前期的分析工作就完成了测砂,下面

開始寫爬蟲吧

先初始化幾個(gè)要用到的全局變量

categaries = {}                        # 分類列表
person = {}                            # 人名列表
PATH = os.getcwd()                     # 根目錄路徑
forbidchar = r'<|>|/|\\|\||:|"|\*|\?'  # 系統(tǒng)禁止用作文件名的字符茵烈,正則表達(dá)式

一、圖片下載函數(shù)

首先砌些,我們要下載網(wǎng)站上所有的圖片呜投,所以需要有一個(gè)給定圖片鏈接就能下載下來的函數(shù):

def downloadimg(link, name):            # link為圖片鏈接加匈,name為圖片名字
    data = urlopen(link, timeout=10)    # 打開連接
    tname = name+".jpg"                 # 給圖片命名
    with open(tname, "ab") as code:     # 以追加二進(jìn)制模式打開文件,并保存數(shù)據(jù)
        code.write(data.read())
    print(tname+" is done.")            # 打印提示文字

但這還不夠仑荐,因?yàn)榻?jīng)常會(huì)碰到鏈接沒有響應(yīng)的情況雕拼,所以加上異常處理

def downloadimg(link, name):
    name = re.split(forbidchar, name)
    name = '.'.join(name)     # 通過re模塊的split,將windows不支持的文件名符號(hào)粘招,全部換成'.'
    for i in range(10):
        time.sleep(0.5) # 照顧別人服務(wù)器的帶寬啥寇,適當(dāng)加點(diǎn)延時(shí)。洒扎。辑甜。加多少看你心情
        try:
            data = urlopen(link, timeout=10)
            tname = name+".jpg"
            with open(tname, "ab") as code:
                code.write(data.read())
            print(tname+" is done.")
            break
        except Exception:
            time.sleep(3) # 多數(shù)情況下,上面的語句中只有urlopen會(huì)出現(xiàn)無響應(yīng)的異常袍冷,這時(shí)等待三秒磷醋,重新發(fā)送請(qǐng)求

二、圖集下載函數(shù)

更進(jìn)一步的胡诗,我們要處理一個(gè)給定鏈接的圖集子檀,首先我們寫一個(gè)下載當(dāng)前頁面的主要圖片的功能

def downloaditem(link, ):
    html = urlopen(link, timeout=100)          # 打開鏈接
    bsObj = BeautifulSoup(html, "html.parser") # 用bs解析html

    for center in bsObj.findAll("center"):     # 找到所有的center標(biāo)簽
        for img in center.findAll("img"):      # 找到其中包含img標(biāo)簽的
            boola = downloadimg(img.attrs['src'], img.attrs['alt'])
                                               # 下載image,并以圖片的alt屬性內(nèi)容給圖片命名

但這還沒完乃戈,記得前面提到的頁面列表么褂痰,我們還要繼續(xù)下載 下一頁 的圖片。于是繼續(xù)

def downloaditem(link, ):
    html = urlopen(link, timeout=100)
    bsObj = BeautifulSoup(html, "html.parser")

    for center in bsObj.findAll("center"):
        for img in center.findAll("img"):
            boola = downloadimg(img.attrs['src'], img.attrs['alt'])
#---------------------------------------------------------------------------
    page = bsObj.find("div", {"id":"pages"})   # 找到所有id屬性為pages的div標(biāo)簽
    for a in page.findAll("a", {"class":"a1"}):
                                               # 找到其中class屬性為a1的a標(biāo)簽
        if re.search(re.compile(r'下一頁'), a.getText()):
                                               # 如果標(biāo)簽內(nèi)容包含下一頁
            number = re.search(re.compile(r"http://www\.meitulu\.com/.*?_([0-9]*?)\.html"), a.attrs['href'])
                                               #用正則表達(dá)式匹配鏈接中的頁碼
            if number:                         #如果匹配成功症虑,失敗時(shí)number為None
                link = number.group(0)         #提取頁面鏈接
                number = number.group(1)       #提取頁碼
                if number != page.find('span').getText():
                                               #如果鏈接的頁碼跟當(dāng)前頁碼不同缩歪,則不是最后一頁,
                    print("download deeper...")#輸出提示信息
                    downloaditem(link)         #繼續(xù)下載下一頁

完善一下代碼谍憔,添加異常捕捉和延時(shí)

def downloaditem(link, ):
    for i in range(10):
        time.sleep(1)
        try:
            html = urlopen(link, timeout=100)
            break
        except Exception:
            print("Url Erroe")
            time.sleep(2)

    for i in range(10):
        try:
            bsObj = BeautifulSoup(html, "html.parser")
            break
        except Exception:
            print("Soup Error")

    for center in bsObj.findAll("center"):
        for img in center.findAll("img"):
            boola = downloadimg(img.attrs['src'], img.attrs['alt'])

    time.sleep(2)
    page = bsObj.find("div", {"id":"pages"})
    for a in page.findAll("a", {"class":"a1"}):
        if re.search(re.compile(r'下一頁'), a.getText()):
            number = re.search(re.compile(r"http://www\.meitulu\.com/.*?_([0-9]*?)\.html"), a.attrs['href'])
            if number:
                link = number.group(0)
                number = number.group(1)
                if number != page.find('span').getText():
                    print("download deeper...")
                    downloaditem(link)

三匪蝙、獲取人名分類下的所有圖集鏈接

def downloadperson(link, name):
    name = re.split(forbidchar, name)
    name = '.'.join(name)                      # 跟圖片文件名原理一樣,替換被禁止的字符
    personitems = {}

    if not os.path.exists(name):               # 檢查這個(gè)人的文件夾之前有沒有創(chuàng)建
        os.mkdir(name)                         # 如果沒有就創(chuàng)建一個(gè)
    os.chdir(name)                             # 進(jìn)入這個(gè)目錄

    html = urlopen(link, timeout=100)          # 打開鏈接
    bsObj = BeautifulSoup(html, "html.parser") # 用bs解析


    for boxs in bsObj.findAll("div", {"class":"boxs"}): # 找到裝載圖片集的<div>標(biāo)簽
        for li in boxs.findAll("li"):                   # 處理每一個(gè)圖片集
            for p in li.findAll('p', {"class":"p_title"}): # 找到包含圖片鏈接的p標(biāo)簽
                psn = p.find('a')
                personitems[psn.getText()] = psn.attrs['href'] # 用文件名作為key給字典添加圖集鏈接

    PATHtmp = os.getcwd()                      # PATHtmp是這一層人名文件夾的路徑
    for key in personitems:                    # 遍歷字典习贫,下載每一個(gè)圖集
        print('\n', "downloading ", key, '\n')
        if not os.path.exists(key):            # 檢驗(yàn)文件夾是否存在
            os.mkdir(key)
        os.chdir(key)                          # 進(jìn)入文件夾
        downloaditem(personitems[key])         # 下載圖集
        os.chdir(PATHtmp)                      # 回到上一層目錄逛球,這里用的絕對(duì)路徑,避免中途被打斷導(dǎo)致后面的下載也出現(xiàn)錯(cuò)誤

    os.chdir(PATH)                             # 回到根目錄

完善代碼苫昌,添加異常捕捉和延時(shí)颤绕,這里因?yàn)橥粋€(gè)人沒有發(fā)現(xiàn)有多頁的情況,所以沒有處理頁面列表的代碼

def downloadperson(link, name):
    name = re.split(forbidchar, name)
    name = '.'.join(name)
    personitems = {}

    if not os.path.exists(name):
        os.mkdir(name)
    os.chdir(name)

    for i in range(10):
        time.sleep(1)
        try:
            html = urlopen(link, timeout=100)
            break
        except Exception:
            time.sleep(2)
            print("Url Erroe")

    for i in range(10):
        try:
            bsObj = BeautifulSoup(html, "html.parser")
            break
        except Exception:
            print("Soup Error")

    for boxs in bsObj.findAll("div", {"class":"boxs"}):
        for li in boxs.findAll("li"):
            try:
                for p in li.findAll('p', {"class":"p_title"}):
                    print('\n',p,'\n')
                    psn = p.find('a')
                    personitems[psn.getText()] = psn.attrs['href']
            except:
                print("Find Error")

    PATHtmp = os.getcwd()
    for key in personitems:
        print('\n', "downloading ", key, '\n')
        if not os.path.exists(key):
            os.mkdir(key)
        os.chdir(key)
        downloaditem(personitems[key])
        os.chdir(PATHtmp)

    os.chdir(PATH)

四祟身、獲得分類下所有人名的分類鏈接

def getperson(link,):
    for i in range(10):
        time.sleep(1)
        try:
            html = urlopen(link, timeout=100)           # 打開連接
            break
        except Exception:
            time.sleep(2)
            print("Url Erroe")

    for i in range(10):
        try:
            bsObj = BeautifulSoup(html, "html.parser")  # bs解析
            break
        except Exception:
            print("Soup Error")

    for boxs in bsObj.findAll("div", {"class":"boxs"}): # 獲取分類下包含圖集的標(biāo)簽
        for li in boxs.findAll("li"):                   # 逐個(gè)圖集處理
            try:
                for a in li.findAll('p'):
                    print(a.getText())                  # 輸出圖集提示信息
                    name = re.search(re.compile(r'^模特:(.*?)$'), a.getText())
                    if name:
                        psn = a.find('a')               # 嘗試查找人名分類頁面鏈接
                        person[psn.getText()] = psn.attrs['href']
            except:                                     # 如果找不到分類頁面奥务,則直接下載圖集
                print("downloading item..."+name.group(1))
                item = li.find('p', {"class":"p_title"}).find("a")
                print(item.getText())
                if not os.path.exists(name.group(1)):
                    os.mkdir(name.group(1))             # 創(chuàng)建人名文件夾
                os.chdir(name.group(1))                 # 進(jìn)入人名文件夾
                print(name.group(1))
                name = item.getText()                   # 提取圖集
                name = re.split(forbidchar, name)       # 處理圖集名(文件夾名)
                name = '.'.join(name)
                if not os.path.exists(name):
                    os.mkdir(name)                      # 創(chuàng)建圖集文件夾
                os.chdir(name)                          # 進(jìn)入圖集文件夾
                downloaditem(item.attrs['href'])        # 下載圖集
                os.chdir(PATH)                          # 回到根目錄


    time.sleep(3)                                       # 延時(shí)
    page = bsObj.find("div", {"id":"pages"})            # 處理下一頁問題,原理同downloaditem函數(shù)
    for a in page.findAll("a", {"class":"a1"}):
        if re.search(re.compile(r'下一頁'), a.getText()):
            number = re.search(re.compile(r"http://www\.meitulu\.com/t/.*?([0-9]*?)\.html"), a.attrs['href'])
            link = number.group(0)
            number = number.group(1)
            if number != page.find('span').getText():
                print("scrap deeper...")
                getperson(link)
                break

五袜硫、主函數(shù)

if __name__ == "__main__":
    for i in range(10):
        time.sleep(1)
        try:
            html = urlopen("http://www.meitulu.com", timeout=100) # 打開首頁鏈接
            break
        except Exception:
            print("Url Erroe")
            time.sleep(2)

    for i in range(10):
        try:
            bsObj = BeautifulSoup(html, "html.parser")            # bs解析
            break
        except Exception:
            print("Soup Error")

    for a in bsObj.find("li", {"id":"tag"}).find("ul", {"id":"tag_ul"}).findAll("a"):
        categaries[a.getText()] = a.attrs['href'] # 獲取所有分類首頁的鏈接氯葬,以分類名為key

    for key in categaries:
        time.sleep(3)
        print(i,"loading page..."+key)
        getperson(categaries[key])                # 獲取每一個(gè)分類下的所有人名鏈接

    for key in person:
        downloadperson(person[key], key)          # 下載每一個(gè)人名下的所有圖集

總結(jié)

完整代碼在這里:<a >simplespider.py</a>
我在代碼中延時(shí)加的比較多,所以運(yùn)行起來有些慢婉陷,但畢竟這只是個(gè)練習(xí)帚称,照顧一下別人服務(wù)器比較好= =官研。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市闯睹,隨后出現(xiàn)的幾起案子阀参,更是在濱河造成了極大的恐慌,老刑警劉巖瞻坝,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛛壳,死亡現(xiàn)場離奇詭異,居然都是意外死亡所刀,警方通過查閱死者的電腦和手機(jī)衙荐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浮创,“玉大人忧吟,你說我怎么就攤上這事≌杜” “怎么了溜族?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長垦沉。 經(jīng)常有香客問我煌抒,道長,這世上最難降的妖魔是什么厕倍? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任寡壮,我火速辦了婚禮,結(jié)果婚禮上讹弯,老公的妹妹穿的比我還像新娘况既。我一直安慰自己,他們只是感情好组民,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布棒仍。 她就那樣靜靜地躺著,像睡著了一般臭胜。 火紅的嫁衣襯著肌膚如雪莫其。 梳的紋絲不亂的頭發(fā)上杠巡,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天踪危,我揣著相機(jī)與錄音,去河邊找鬼。 笑死吕晌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的临燃。 我是一名探鬼主播睛驳,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烙心,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了乏沸?” 一聲冷哼從身側(cè)響起淫茵,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹬跃,沒想到半個(gè)月后匙瘪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝶缀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年丹喻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翁都。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碍论,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出柄慰,到底是詐尸還是另有隱情鳍悠,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布坐搔,位于F島的核電站藏研,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏概行。R本人自食惡果不足惜遥倦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望占锯。 院中可真熱鬧袒哥,春花似錦、人聲如沸消略。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艺演。三九已至却紧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胎撤,已是汗流浹背晓殊。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伤提,地道東北人巫俺。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像肿男,于是被迫代替她去往敵國和親介汹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子却嗡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容