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