获取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() #调用函数查找用户