1. 程式人生 > >Python爬蟲(1)------爬取網站圖片

Python爬蟲(1)------爬取網站圖片

初學爬蟲的學習流程

環境

python 3.6
使用 urlib庫進行爬取內容

熟悉爬蟲

首先對百度進行爬取

# -*- coding: utf-8 -*-
import urllib.request

url = 'http://www.baidu.com'
resp = urllib.request.urlopen(url)
print(resp.read())

使用urllib.request的urlopen()方法訪問一個url。
輸入伺服器返回的內容。

b'<!DOCTYPE html>\n<!--STATUS OK--><title
>
\xe7\x99\xbe\xe5\xba\xa6\xe4\xb8\x80\xe4\xb8\x8b\xef\xbc\x8c\xe4\xbd\xa0\xe5\xb0\xb1\xe7\x9f\xa5\xe9\x81\x93</title>\n \r\n\r\n<style id="css_index" index="index" type="text/css">html,body{height:100%}\nhtml{overflow-y:auto}\nbody{font:12px arial;text-align:;background:#fff}\nbody,p,form
,ul,li{margin:0;padding:0;list-style:none}\nbody,form,#fm{position:relative}\ntd{text-align:left}\nimg{border:0}\na{color:#00c}\na:active{color:#f60}\ninput{border:0;padding:0}\n#wrapper{position:relative;_position:;min-height:100%}\n#head{padding-bottom:100px;text-align:center;*z-index:1}\n#ftCon{height:50px;position
:absolute
;bottom:47px;text-align:left;width:100%;margin:0 auto;z-index:0;overflow:hidden
}\n.ftCon-Wrapper{overflow:hidden;margin:0 auto;text-align:center;*width:640px}\n.qrcodeCon{text-align:center;position:absolute;bottom:140px;height:60px;width:100%}\n#qrcode{display:inline-block;*float:left;*margin-top:4px}\n#qrcode .qrcode-item{float:left}\n#qrcode .qrcode-item-2{margin-left:33px}\n#qrcode .qrcode-img{width:60px;height:60px}\n#qrcode .qrcode-item-1 .qrcode-img{background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/qrcode/zbios_efde696.png) 0 0 no-repeat}\n#qrcode .qrcode-item-2 .qrcode-img{background:url(http://s1.bdstatic.com/r/www/cache/static/home/img/qrcode/nuomi_365eabd.png) 0 0 no-repeat}\n@media only screen and (-webkit-min-device-pixel-ratio:2){#qrcode .qrcode-item-1 .qrcode-img{background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/qrcode/zbios_x2_9d645d9.png);background-size:60px 60px}\n#qrcode .qrcode-item-2 .qrcode-img{background-image:url(http://s1.bdstatic.com/r/www/cache/static/home/img/qrcode/nuomi_x2_55dc5b7.png);background-size:60px 60px}}\n#qrcode .qrcode-text{color:#999;line-height:23px;margin:3px 0 0}\n#qrcode .qrcode-text a{color:#999;text-decoration:none}\n#qrcode .qrcode-text p{text-align:center}\n#qrcode .qrcode-text b{color:#666;font-weight:700}\n#qrcode .qrcode-text span{letter-spacing:1px}\n#ftConw{display:inline-block;text-align:left;margin-left:33px;line-height:22px;position:relative;top:-2px;*float:right;*margin-left:0;*position:static}\n#ftConw,#ftConw a{color:#999}\n#ftConw{text-align:center;margin-left:0}\n.bg{background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_5859e57.png);background-repeat:no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_d5b04cc.gif)}

只貼出部分程式碼,可以看到爬取的內容是亂碼的。

# -*- coding: utf-8 -*-
import urllib.request

url = 'http://www.baidu.com'
resp = urllib.request.urlopen(url)
print(resp.read().decode('utf-8'))

對輸出進行utf-8的轉碼即可正常顯示。

爬取虎嗅網的熱文

為了使我們的爬蟲看起來更像是瀏覽器訪問的我們一般對請求新增請求頭資訊。
不然可能會得到 403 Forbidden的網頁資訊

req = urllib.request.Request(target_url)
    req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36")

這裡添加了鍵為”User-Agent”的瀏覽器資訊。
獲取虎嗅首頁html

import urllib
import urllib.request

url = 'https://www.huxiu.com'


def get_html(target_url):
    req = urllib.request.Request(target_url)
    req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36")
    response = urllib.request.urlopen(req)
    return response.read().decode('utf-8')


html = get_html(url)
print(html)

獲得首頁的html,在瀏覽器中開啟爬取的html。
按下F12鍵進入開發者模式。
Exler
點選 1 處,然後點選網頁中的任何地方就能跳到該元素所在的程式碼處,我們可以清楚的看見有一些 li 標籤整齊的排列在其中。
Exler
可以發現每個 li 裡面div塊的css都是hot-article-img
利用BeautifulSoup庫來對爬取到的html頁面進行解析

def use_bs_get_list(html):
    soup = BeautifulSoup(html, "html.parser")  # use html.parser dissection
    all_list = soup.select('.hot-article-img')
    return all_list


hot_article_list = use_bs_get_list(html)
  1. 初始化BeautifulSoup(html頁面,解析器)。
  2. 利用 .hot-article-img 我們要找的div塊用的css名,BeautifulSoup能很便捷的幫助我們解析。
  3. 輸出得到的list。
<div class="hot-article-img">
<a href="/article/242516.html" target="_blank" title="忽如一夜朝鮮來">
<!--視訊和圖片保留一個-->
<img src="https://img.huxiucdn.com/article/cover/201805/03/070310664833.jpg?imageView2/1/w/280/h/210/|imageMogr2/strip/interlace/1/quality/85/format/jpg"/>
</a>
</div>

可以看到每一個class=”hot-article-img”的div塊以list的元素輸出。

解析list的每個item得到文章的img title url三個資訊

def get_hot_article_img_title(all_list):
    hot_article = []
    for news in all_list:
        # get <a ....>....</a>
        a_tag = news.select('a')
        # a[0]['title'] is none
        if len(a_tag) > 0:
            # article href
            try:
                href = url + a_tag[0]['href']
            except Exception:
                href = ''
            # article img url
            try:
                # get img tag(inside a tag) img tag's src
                img_url = a_tag[0].select('img')[0]['src']
            except Exception:
                img_url = ''
            try:
                title = a_tag[0]['title']
            except Exception:
                title = 'none'
            hot_article.append("href:" + href + '\n' + "title:" + title + '\n' + "img_url:" + img_url + '\n')
    return hot_article

利用BeautifulSoup處理的list每一個項都是tag物件仍舊可以對其中的標籤元素進行選擇解析。
首先是得到div裡的a標籤應為有兩個a標籤所以我們選第一個也就是a_tag[0]。再利用a_tag[0][屬性名]去選擇a標籤內某個屬性的內容。
Exler
文章url在a標籤的href內,當然還要和虎嗅的官網url拼接,文章名在title內,而文章圖片的url是在a標籤內部的img標籤的src裡。

href:https://www.huxiu.com/article/242516.html
title:忽如一夜朝鮮來
img_url:https://img.huxiucdn.com/article/cover/201805/03/070310664833.jpg?imageView2/1/w/280/h/210/|imageMogr2/strip/interlace/1/quality/85/format/jpg

最後儲存的項是這樣的。
對網頁html規律分析是十分重要的。

網站圖片的爬取

爬取首頁列表

爬取熱門美女這個列表
Exler

url = "https://www.meitulu.com"

def get_html(target_url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko)",
        "Accept - Encoding": "gzip, deflate, br",
        "Referer": "https://www.meitulu.com/"
    }
    req = urllib.request.Request(target_url, headers=headers)
    response = urllib.request.urlopen(req)
    content = response.read()
    # b'<!'   b=31
    if content[0] == 31:
        buff = BytesIO(content)
        f = gzip.GzipFile(fileobj=buff)
        res = f.read().decode('utf-8')
        return res
    # picture details is not gzip
    return content.decode('utf-8')

應為有網頁是用gzip壓縮的,所以這邊有個判斷。

獲得每個列表項的url

def get_xiaojiejie_list(html, parsing_rules):
    xiaojiejie_list = []
    soup = BeautifulSoup(html, "html.parser")
    tat_list = soup.select(parsing_rules)
    tat_list = tat_list[0].select('li')
    for var in tat_list:
        url = var.select('a')[0]['href']
        name = var.select('img')[0]['alt']
        xiaojiejie_list.append({'name': name, 'url': url})
    return xiaojiejie_list


hot_gril_list = get_xiaojiejie_list(html, 'ul[class="hot_meinv"]')

在html內容裡獲取class為hot_meinv的ul標籤
構建元素項為字典型別(包含名字 和 對應的url)的list

{'name': '森下悠裡', 'url': 'https://www.meitulu.com/t/yuuri-morishita/'}, 
{'name': '鈴木愛理', 'url': 'https://www.meitulu.com/t/airi-suzuki/'},
{'name': '柏木由紀', 'url': 'https://www.meitulu.com/t/kashiwagi-yuki/'}

獲取相簿資訊

獲得了首頁每個小姐姐url之後迴圈進入
這裡只貼出一個的爬取方法。
Exler
可以看到每一個相簿的url都安安靜靜的放在這裡。

def go_to_photo_list(hot_girl_list):
    for var in hot_girl_list:
        path = 'picture/' + var['name']
        if os.path.exists(path) is False:
            os.mkdir(path, 777)
        else:
            continue
        second_level_html = get_html(var['url'])
        url_list = get_item_girl_img_list(second_level_html, 'ul[class="img"]')

根據每個小姐姐的名字建立資料夾,有過的就不爬了。
然後獲取小姐姐相簿頁的html。
這裡匯入一個os庫,用來對資料夾進行操作。
獲得class=img的ul標籤內所有的li並對其進行解析。

def get_item_girl_img_list(html, parsing_rules):
    item_list = []
    soup = BeautifulSoup(html, "html.parser")
    tat_list = soup.select(parsing_rules)
    tat_list = tat_list[0].select('li')
    for var in tat_list:
        url = var.select('a')[0]['href']
        name = var.select('img')[0]['alt']
        count = var.select('p')[0].text.split(' ')[1]
        # count = var.select()
        item_list.append({'name': name, 'url': url, 'count': count})
    return item_list

經過BeautifulSoup的篩選tat_list中只有一個內容就是ul標籤及其裡面的內容所以我們取tat_list[0]中的所有li
再對每個li進行解析 得到圖片的url 相簿名 以及相簿中圖片的數量
最終tat_list中的內容

[<li>
<a href="https://www.meitulu.com/item/6991.html" target="_blank"><img alt="[VYJ] No.114 柏木由紀 四刊全集套圖[237]" height="300" src="https://mtl.ttsqgs.com/images/img/6991/0.jpg" width="220"/></a>
<p><span>16</span>圖片: 237 張(1280X960)</p>
<p>機構: <a class="tags" href="https://www.meitulu.com/t/vyj/" target="_blank">VYJ</a></p>
<p>模特: <a class="tags" href="https://www.meitulu.com/t/kashiwagi-yuki/" target="_blank">柏木由紀</a></p>
<p>標籤: <a class="tags" href="https://www.meitulu.com/t/ribenmeinv/" target="_blank">日本美女</a> <a class="tags" href="https://www.meitulu.com/t/qingchun/" target="_blank">清純</a> <a class="tags" href="https://www.meitulu.com/t/tianmei/" target="_blank">甜美</a> <a class="tags" href="https://www.meitulu.com/t/meishaonv/" target="_blank">美少女</a> <a class="tags" href="https://www.meitulu.com/t/mengmeizi/" target="_blank">萌妹子</a></p>
<p class="p_title"><a href="https://www.meitulu.com/item/6991.html" target="_blank">[VYJ] No.114 柏木由紀 四刊全集套圖</a></p>
</li>, <li>
<a href="https://www.meitulu.com/item/6980.html" target="_blank"><img alt="[VYJ] No.111 柏木由紀 Yuki Kashiwagi [22]" height="300" src="https://mtl.ttsqgs.com/images/img/6980/0.jpg" width="220"/></a>
<p><span>11</span>圖片: 22 張(1280X960)</p>
<p>機構: <a class="tags" href="https://www.meitulu.com/t/vyj/" target="_blank">VYJ</a></p>
<p>模特: <a class="tags" href="https://www.meitulu.com/t/kashiwagi-yuki/" target="_blank">柏木由紀</a></p>
<p>標籤: <a class="tags" href="https://www.meitulu.com/t/qingchun/" target="_blank">清純</a> <a class="tags" href="https://www.meitulu.com/t/tianmei/" target="_blank">甜美</a> <a class="tags" href="https://www.meitulu.com/t/ribenmeinv/" target="_blank">日本美女</a> <a class="tags" href="https://www.meitulu.com/t/mengmeizi/" target="_blank">萌妹子</a></p>
<p class="p_title"><a href="https://www.meitulu.com/item/6980.html" target="_blank">[VYJ] No.111 柏木由紀 Yuki Kashiwagi </a></p>
</li>,   ......

li標籤為list每個元素項

接下去是對list中每個item標籤的解析

        for item in url_list:
            img_html = get_html(item['url'])
            print('now we go to url:' + item['url'])
            get_img(img_html, count, item['url'], var['name'], item['count'])
            print('above name is:' + item['name'])
            count = count + 1

進如相簿爬取圖片。
Exler

爬取圖片

第二頁第三頁等等,相簿內之後的頁數只要利用首頁的url+”_頁數”就好了。

def get_img(img_html, count, img_url, girl_name, img_count):
    img_count = int(img_count)
    img_list = []
    i = 0
    page = 2
    path = 'picture/' + girl_name + '/' + str(count)
    if os.path.exists(path) is False:
        os.mkdir(path, 777)
    target_url = img_url
    target_url = target_url[:-5] + '_' + str(page) + '.html'
    while i < img_count:
        soup = BeautifulSoup(img_html, "html.parser")
        img_url_list = soup.select('center')[0].select('img')
        for var in img_url_list:
            a = var['src']
            i = i + 1
            img_list.append(a)
        if i < img_count:
            # print(target_url)
            # i = 38 but img_count = 40 but img only 38 so break
            try:
                img_html = get_html(target_url)
            except urllib.error.HTTPError:
                break
            page = page + 1
            target_url = target_url.split("_")[0] + "_" + str(page) + ".html"
    save_img(img_list, path)


def save_img(img_list, path):
    count = 0
    for item in img_list:
        if os.path.exists(path + '/' + str(count) + ".jpg") is False:
            f = open(path + '/' + str(count) + ".jpg", 'wb')
            headers = {
                "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko)",
                "Accept - Encoding": "gzip, deflate, br",
                "Referer": "https://www.meitulu.com/"
            }
            req = urllib.request.Request(item, headers=headers)
            try:
                response = urllib.request.urlopen(req)
            except urllib.error.HTTPError:
                print('error again')
                f.close()
                save_img(img_list, path)
            else:
                if (response.status > 199 and response.status < 300):
                    try:
                        f.write(response.read())
                    except Exception:
                        print('save file error')
            f.close()
        count = count + 1
    print('success')

得到每張圖片的url 爬下來儲存到本地對應的資料夾中就好了。

文章從簡到繁,雖然講解不是特別細緻,但主要是體現一下學習流程,關鍵還是自己的體會。程式碼