python3多线程爬取微博配图相册,可自动获取session【简单,快速】

@python爬取微博配图相册,可自动获取sessionTOC
只需要设置你的用户名,密码和要爬取用户的UID即可。
wbname=“xxxx”
wbpwd=“xxxx”
uid = 1912992047

2019.06.19 增加多线程,此处提供一个轮子,速度比以前增加10倍

主要是按照自己的习惯优化和增加了自动获取session。
提升1:修改下根据python wb.py uid这样,就不需要每次打开py文件进行修改了。
提升2:自己增加断点功能(相同名字图片不会重复下载,无需开发)和
调用人脸识别进行颜值打分判断下载(百度人脸识别接口)。

困难1:登陆失败了一次,让我滑动按钮验证。验证完就又可以了,这个不知道怎么越过。遇到的人多的话,我再看吧。
https://m.weibo.cn/ 也可以首页登陆下,再执行脚本就可以了。

困难2:sso登录有时候会报错,应该属于登录接口自己的问题。等个几分钟再执行就好。
场景如下:
“‘NoneType’ object has no attribute ‘string’” “‘NoneType’ object has no attribute ‘text’”

如果还有什么想优化的地方,可以和我留言

1.当前目录下建 MulTool.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys
import queue
import threading

class Worker(threading.Thread):    # 处理工作请求
    def __init__(self, workQueue, resultQueue, **kwds):
        threading.Thread.__init__(self, **kwds)
        self.setDaemon(True)
        self.workQueue = workQueue
        self.resultQueue = resultQueue


    def run(self):
        while 1:
            try:
                callable, args, kwds = self.workQueue.get(False)    # get task
                res = callable(*args, **kwds)
                self.resultQueue.put(res)    # put result
            except queue.Empty:
                break

class WorkManager:    # 线程池管理,创建
    def __init__(self, num_of_workers=10):
        self.workQueue = queue.Queue()    # 请求队列
        self.resultQueue = queue.Queue()    # 输出结果的队列
        self.workers = []
        self._recruitThreads(num_of_workers)

    def _recruitThreads(self, num_of_workers):
        for i in range(num_of_workers):
            worker = Worker(self.workQueue, self.resultQueue)    # 创建工作线程
            self.workers.append(worker)    # 加入到线程队列


    def start(self):
        for w in self.workers:
            w.start()
    
    def start(self):
        for w in self.workers:
            w.start()

    def wait_for_complete(self):
        while len(self.workers):
            worker = self.workers.pop()    # 从池中取出一个线程处理请求
            worker.join()
            if worker.isAlive() and not self.workQueue.empty():
                self.workers.append(worker)    # 重新加入线程池中
        #print("All jobs were complete.")


    def add_job(self, callable, *args, **kwds):
        self.workQueue.put((callable, args, kwds))    # 向工作队列中加入请求

    def get_result(self, *args, **kwds):
        return self.resultQueue.get(*args, **kwds)

2 weibo.py 的内容

#coding:gbk
import os
import re
import sys
import time
import json
import requests
import MulTool
from bs4 import BeautifulSoup as bs

#uid即进入对方微博主页后网址部分/u/后的那一串数字
#https://weibo.cn/u/1912992047?page=1
wbname=“xxx”
wbpwd=“xxx”
uid = 1912992047
url = 'https://weibo.cn/u/' + str(uid)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Referer': 'https://passport.weibo.cn/signin/login',
    'Connection': 'close',
    'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'
    }

pictrue_num = 0 #当前已爬取的图片总数
Loginsession = requests.session()

def GetPageAddr():
    GetSession()
    r = Loginsession.get(url, headers=headers)
    soup = bs(r.text, 'lxml')
    # 所访问的微博用户名
    weibo_user_name = soup.find('title').text.replace(u'的微博', '')

    # 存放图片的根目录
    rootDir = 'D://微博配图相册//' + weibo_user_name + '//'
    if not os.path.exists(rootDir):
        os.makedirs(rootDir)
    
    # 微博总页数,通过审查元素可知
    totalPage = int(soup.find('input', attrs={'name':'mp'}).attrs['value'])
    print('总共检测到%d页微博页面' % totalPage)
    
    for pagenum in range(1,totalPage+1):
        GetPageItems(rootDir,pagenum)
    print('总共爬取了%d张图片,存放在%s目录下' % (pictrue_num, rootDir))
        
def GetPageItems(dirpath,pagenum):
    # 每页微博的URL的列表
    weibo_url = url + '?page=' + str(pagenum)
    r = Loginsession.get(weibo_url, headers=headers)
    soup = bs(r.text, 'lxml')
    
    #每条微博所对应的标签代码块列表
    weibo_tags_list = soup.find_all('div', attrs={'class': 'c'}, id=True)
    
    wma = MulTool.WorkManager(8)
    #微博发送时间与微博配图的字典
    for u in range(len(weibo_tags_list)):
        print('正在爬取第%d页第%d条微博' % (pagenum, u + 1))
        wma.add_job(GetOneAlbum,dirpath,weibo_tags_list[u])
    wma.start()
    wma.wait_for_complete()
    print('第%d页微博爬取完毕,开始生成图片' % (pagenum))
        
        
def GetOneAlbum(dirpath,weibo_tag):       
    #获取微博发送时间
    try:
        hms = ' '.join(weibo_tag.find('span', attrs={'class': 'ct'}).string.replace('\xa0', ' ').replace(':', '-').split(' ')[:2])
    except:
        hms = ' '.join(weibo_tag.find('span', attrs={'class': 'ct'}).text.replace('\xa0', ' ').replace(':', '-').split(' ')[:2])
        
    if weibo_tag.find('span', attrs={'class': 'cmt'}):
        print("转发\n")
        #return; #本行如果注释掉就和下载转发的微博
    t=1    
    #该条微博若带有组图,获取组图中所有图片的URL
    if weibo_tag.find('a', text=re.compile('组图')):
        imgs_url = weibo_tag.find('a', text=re.compile('组图')).attrs['href']
        html = Loginsession.get(imgs_url, headers=headers)
        imgs_soup = bs(html.text, 'html.parser')
        imgs_tags_List = imgs_soup.find_all('img', alt='图片加载中...')
        img_urls_list = [imgs_tag.attrs['src'].replace('thumb180', 'large') for imgs_tag in imgs_tags_List]
        #imgs_urls_dic[hms] = img_urls_list
    #该条微博仅有一张配图,或者没有图片,获取图片的URL
    else:
        img_tags_List = weibo_tag.find_all('img', alt='图片')
        img_urls_list = [img_tag.attrs['src'].replace('wap180', 'large') for img_tag in img_tags_List]
        #imgs_urls_dic[hms] = img_urls_list
    print("该条微博还有%d 张图片" %len(img_urls_list))
    wmb = MulTool.WorkManager(6)
    for u in range(len(img_urls_list)):
        wmb.add_job(SaveImg,dirpath,hms,img_urls_list[u],t)
        t=t+1
    wmb.start()
    wmb.wait_for_complete()
    
def SaveImg(dirpath,hms,img_url,index):
    global pictrue_num
    #生成图片的存放路径,图片被命名为微博发送时间
    path = dirpath + hms
    
    #如果一条微博在同一时间发送了多张图片(即组图)的命名处理
    if(img_url[-3:]=="gif"):
        path = path + '-' + str(index+1)+'.gif'
    else:
        path = path + '-' + str(index+1)+'.jpg'
    try:
        if not os.path.exists(path):
            r = Loginsession.get(img_url)
            with open(path, 'wb') as f:
                f.write(r.content)
                pictrue_num = pictrue_num + 1
            time.sleep(1)
        else:
            print('%s已经存在' % path)
            pictrue_num = pictrue_num + 1
        print('success,成功爬取第%d张图片' % pictrue_num)
    except Exception as e:
        print('爬取失败,%s' % img_url)

def GetSession():
    loginApi = 'https://passport.weibo.cn/sso/login'
    loginPostData = {
        'username':wbname,
        'password':wbpwd,
        'savestate':1,
        'r':'',
        'ec':'0',
        'pagerefer':'',
        'entry':'mweibo',
        'wentry':'',
        'loginfrom':'',
        'client_id':'',
        'code':'',
        'qq':'',
        'mainpageflag':1,
        'hff':'',
        'hfp':''
    }
    r = Loginsession.post(loginApi,data=loginPostData,headers=headers)
    try:
        if r.status_code == 200 and json.loads(r.text)['retcode'] == 20000000:
            print("successful")
        else:
            #print(r.status_code)
            #print(r.text)
            print("Logon failure!")
    except Exception as e:
        print(e)
        print("Logon failure2!")
        
GetPageAddr();

主要参考:
https://blog.youkuaiyun.com/cool_flag/article/details/78992628

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值