獲取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() #調用函數查找用戶