python-爬蟲之批量爬取微博指定用戶高清圖片


獲取cookie

  用瀏覽器登錄微博:新浪微博

  注意事項:在登錄之前先按F12,確保跳出以下界面,試過很多次找不到cookie就是因為沒先打開這個:

  

  然后登錄微博,找到自己的cookie,把cookie保存下來后面用來訪問微博,接下來就可以進入正題了。

  

1.導入模塊

import requests                #訪問微博網站以及數據獲取
import re                      #解析網頁數據
import pyquery as pq           #解析html
import json                    #反序列化
import time            

2.初始化全局變量

為了省事這里采用了簡單粗暴的方法,直接將這些復制在代碼里了,顯得有點丑。也可以更優雅一點,將這些寫在json文件里,然后再讀出來,會顯得好看一些

headers:就是瀏覽器訪問網站時會攜帶這些數據,網站服務器就可以識別了,有些網站如果沒有請求頭會出錯,這個可以在剛剛獲取cookie那里找到。

User-Agent:包含了瀏覽器的版本信息,也可以從這里知道是移動端還是PC端訪問的

Cookie:相當於用戶認證,登錄之后網站會給你設置cookie,帶着這個cookie訪問網站就可以不用重新登錄了。

COOKIE = ""        #雙引號里放剛剛保存的cookie
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',\
    'Cookie': COOKIE
}                     #請求頭
DECODE_DICT={
    '%2F':'/',
    'mw1024':'large'
}                     #這是用來解碼微博圖片url的
URLS=[]              #用來存放圖片url

3.查找用戶

 

1.當我們在微博頁面查找用戶時,可以看到url就是:https://s.weibo.com/user?q=用戶名&Refer=weibo_user,所以通過這個url去訪問即可獲取查找完成后的頁面

 

2.其實一般來說每次找人肯定是那個人在第一個,所以這里的for循環換成直接獲取第一個標簽的url應該也可以,但是這里還是寫了個循環判斷一下

3.pyquery用法跟jQuery一樣,可以方便地找出滿足條件的標簽,通過“.card .info .name”即可找到對應的標簽,通過tag.text()獲取名字,並判斷是否正確

def query_user():
    name=input('>>:').strip()      
    text = req.get('https://s.weibo.com/user?q=%s&Refer=weibo_user'%name, headers=HEADERS).text                 #查找目標用戶
    time.sleep(1)                              
    html=pq.PyQuery(text)                                    #將查找后獲得的html轉成pyquery對象 for tag in html(".card .info .name"):                            #獲取所有帶有用戶名的標簽
        tag = pq.PyQuery(tag)
        if tag.text()==name:                                   
            link=tag.attr('href')
            link='https:'+link
            response = req.get(link.format(name), headers=HEADERS)    #找到標簽里用戶名與目標用戶名一致的標簽,獲取url,訪問該用戶
            text=response.text
            enter_album(text)                         #進入用戶的相冊
            time.sleep(1)
            download_pic()                            #開始下載圖片
       break

4.進入相冊

1.當時為了盡快實現功能所以這個函數寫得有點亂

2.在上面查找到用戶的時候調用了enter_album(html)函數,這個函數就是進入用戶相冊之后進行處理。

  • 進入相冊之后並沒有任何圖片,所以要通過這個相冊的頁面,獲取相冊第一頁的url
  • 用戶相冊除了第一頁,其他頁都是動態渲染的,所以在訪問前一頁的圖片時還要獲得下一頁圖片的相關信息,然后通過這個信息訪問下一頁的圖片。

3.這里用到正則表達式是因為這個相冊的界面是動態渲染的,所以得到的數據並不是html的格式,所以先通過re模塊獲取數據然后拿到html,

因為懶得寫太復雜的表達式,所以只是粗略過濾一下,所以data里的數據並不全是json格式,如果不用try直接就報錯退出了。。。真是偷懶到極致了我。。

4.拿到html后就可以跟上面的方法一樣找到相應的標簽,獲取url,這里直接找了“tab_link”,因為“她的主頁”,"她的相冊","作品"都用到了“tab_link”樣式,所以加了判斷

判斷獲取的href里是否有photos字符串,通過這個url訪問相冊。

 

5.進入相冊后找到運用了“.WB_cardwrap”樣式的標簽,獲取action-data屬性,對這個字符串進行處理獲取相冊下一頁的信息

 

 

6.獲取圖片url:找到'運用了“ph_ar_box”樣式的標簽,獲取action-data屬性,通過對字符串處理獲取到划紅線的子串(這一步在parse_url里實現),這個子串就是圖片的url

def enter_album(html):
    item_dict = {}                                                  #這個字典用來存放下一頁的相關信息 #獲取相冊第一頁的相關信息
    data=re.findall('<script>FM.view\((.*?)\)', html, re.S)         #用正則表達式獲取數據
    url=None
    for item in data:
        try:
            item=json.loads(item)                                   #反序列化
            item=item.get('html')                          
            html=pq.PyQuery(item)
            keyword='photos'
            for tag in html('.tab_link'):
                href=tag.get('href')
                if keyword in href:
                    url='https://weibo.com'+href
                    item_dict['page_id']=re.search('p/(.\d+)/',url).group()[2:-1]
                    break
        except Exception as e:
            continue
#獲取第一頁所有照片的url以及下一頁的相關信息
        if url:
            response = req.get(url,headers=HEADERS)
            htmls=response.content
            data = re.findall('<script>FM.view\((.*?)\)</script>', htmls.decode('utf-8'), re.S)
            for html in data:
                try:
                    html = json.loads(html)
                    html = html.get('html')
                    html = pq.PyQuery(html)
                    next_page=html('.WB_cardwrap').attr('action-data')
                    if next_page:
                        html('.ph_ar_box').each(parse_url)      #獲得此頁所有含有圖片url的標簽,並將此標簽傳到parse_url函數
                        next_page = next_page.split('&')
                        for sub in next_page:
                            sub = sub.split('=')
                            item_dict[sub[0]] = sub[1]
                        get_url(item_dict)                #獲取相冊下一頁的圖片url except Exception as e:
                    continue
            break        

5.圖片url解碼

上面說到圖片的url,還需要解碼變成真正的url,其實就是將里面的一些字符替換了,百度圖片的url也是這樣子的。

def parse_url(index,tag):
    tmp_url=tag.get('action-data').strip("curclear_picSrc=")    #獲取未解碼的圖片url
    url=tmp_url[:tmp_url.find('.jpg')+4]
    for key in DECODE_DICT:
        url=url.replace(key,DECODE_DICT[key])                   #用初始化時的解碼字典進行替換,得到圖片真正的url
    URLS.append("http:"+url)                                    #將圖片url存到URLS列表中

6.獲取相冊下一頁的圖片url

當我們滾動頁面查看下一頁相冊時會看到這個,這是前端給后台發的數據,后台根據這個數據返回數據給前端

 ajwvr:暫時不知道是什么,一直都是6

owner_uid:就是你訪問的用戶的id

viewer_uid:自己的id

since_id:應該是當頁相冊對應的第一條微博的id和最后一條微博的id,還有時間

page:就是相冊的頁碼

ajax_call:可能是ajax回調函數的類型,根據這個參數調用相關的函數。。我猜的。。反正填1就對了

_rnd:時間戳

def get_url(data_dict):
    q_url = 'https://weibo.com/p/aj/album/loading'
    user_data=data_dict
    for i in range(1,10000):                               #這里是從第一頁獲取到最后一頁
        params= {
                    'ajwvr': 6,
                    'type': 'photo',
                    'owner_uid': int(user_data['owner_uid']),
                    'viewer_uid': int(user_data['viewer_uid']),
                    'since_id': user_data['since_id'],
                    'page_id': int(user_data['page_id']),
                    'page': i,
                    'ajax_call': 1,
                    '__rnd': time.time(),
                }
        try:
            url = requests.get(q_url, headers=HEADERS, params=params) #刷新下一頁
            url = url.json().get('data')
            url = pq.PyQuery(url)
            print("page:%d" % i)
            time.sleep(1)
            url('.ph_ar_box').each(parse_url)
            try:
                user_data['since_id'] = url('.WB_cardwrap').attr('action-data')
                user_data['since_id'] = user_data['since_id'][user_data['since_id'].rfind('since_id=') + 9:]
            except Exception as e:                                    #最后一頁則退出
                return None
        except Exception as e:
            print(e)
            continue

7.下載圖片

 最后就是去訪問URLS里的圖片url並保存,這里保存路徑寫死了,可以優化一下自定義路徑

def download_pic():
    global URLS
    for url in URLS:
        try:
            content = req.get(url, headers=HEADERS).content
        except Exception as e:
            continue
        filename = url[url.rfind("/") + 1:]
        with open("test/%s" %  filename, 'wb') as file:
            file.write(content)
        time.sleep(1)
    else:
        URLS = []

8.開始下載

這里可以加個循環去調用query_user(),這樣下載完就不會直接退出了

if __name__=="__main__":
    req=requests.session()        #創建會話
    query_user()                  #調用函數查找用戶


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM