社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

拼多多现重大BUG被“薅羊毛”,教你如何用Python简单褥羊毛

python • 6 年前 • 763 次点击  

前言

从1月20日凌晨开始,拼多多出现巨大漏洞,用户可以领取100元无门槛券。

有大批用户开启“薅羊毛”的节奏,利用无门槛券来充值话费、Q币。拼多多回应称,有黑灰产团伙通过一个过期的优惠券漏洞盗取数千万元平台优惠券,进行不正当牟利。

小编感觉每次这样的消息都貌似最后才知道的。


这里介绍的“羊毛”主是指京东平台的虚拟货币:京豆,如果按每天能褥一波计算,少则有几十京豆,多则一两百也是有可能是。

'''
作者:happyJared
源自:https://blog.csdn.net/qq_28804275/article/details/82085430
'''

基本环境配置

版本:Python3.6

系统:Windows

相关模块:

  • Requests

  • BeautifulSoup4

  • Selenium (配置好Chrome Driver、Firefox Driver或是PhantomJS环境)

京东账号得关联QQ,且当前QQ在线 (用于QQ授权登录京东,可自行扩展登录方式)

实现效果展示

实现代码

Python写的代码已经很简洁了,注释也完善了很多,有兴趣的继续往下看。


wx_turing.py


import time
from urllib.parse import parse_qs

import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.common.exceptions import *
from selenium.webdriver.support.wait import WebDriverWait

# 额外抽取的授权模块
from utils import auth


class QMM(object):
    """借助券妈妈平台褥京东京豆"""

    def __init__(self, sleep=3, months=None, days=None):
        self.timeout, self.months, self.days = sleep, NoneNone
        # 爬取规则
        if months:
            month_interval = months.split('-')
            start_month, end_month = int(month_interval[0]), int(month_interval[-1])
            self.months = list(map(lambda m: '{}月'.format(m), range(start_month, end_month + 1)))
        if days:
            day_interval = days.split('-')
            start_day, end_day = int(day_interval[0]), int(day_interval[-1])
            self.days = list(map(lambda d: '{}日'.format(d), range(start_day, end_day + 1)))
        # 手机店铺(用作提醒输出,可复制链接到手机端领取)
        self.m_shop = []
        # 统计京豆总数
        self.jing_dou = 0

    def _crawl_url(self):
        """ 抓取京豆更新页, 获得店铺京豆领取地址"""

        # 日期更新页
        qmm_collect = 'http://www.quanmama.com/zhidemai/2459063.html'
        bs = BeautifulSoup(requests.get(qmm_collect).text, 'html.parser')
        for link in bs.tbody.find_all('a'):
            text = link.text
            if self.months:
                if not list(filter(lambda m: m in text, self.months)): continue
            if self.days:
                if not list(filter(lambda d: d in text, self.days)): continue

            qmm_detail = link.get('href')

            # 店铺领取页
            resp = requests.get(qmm_detail)
            bs = BeautifulSoup(resp.text, 'html.parser')
            for body in bs.find_all('tbody'):
                for mall in body.find_all('a'):
                    url = self._parse_url(mall.get('href'))
                    if 'shop.m.jd.com' in url:
                        self.m_shop.append(url)
                    else:
                        yield url

    @staticmethod
    def _parse_url(url):
        """提取URL中的url参数"""

        mall_url = parse_qs(url).get('url')
        return mall_url.pop() if mall_url else url

    def start(self):
        """ 登录京东,领取店铺羊毛"""

        malls = set(self._crawl_url())
        print('共有 %d 个可褥羊毛PC端店铺页面' % len(malls))

        m_malls = self.m_shop
        print('共有 %d 个可褥羊毛手机端店铺页面' % len(m_malls))
        for m_mall in m_malls:
            print(m_mall)

        if malls:
            # 登陆京东(Chrome、PhantomJS or FireFox)
            driver = webdriver.Chrome()  # driver = webdriver.PhantomJS()
            jd_login = 'https://passport.jd.com/new/login.aspx'
            driver.get(jd_login)

            # 窗口最大化
            driver.maximize_window()

            # QQ授权登录
            driver.find_element_by_xpath('//*[@id="kbCoagent"]/ul/li[1]/a').click()
            auth.qq(driver)
            time.sleep(self.timeout)

            # 开始褥羊毛
            for i, detail in enumerate(malls):
                driver.get(detail)
                print('%d.店铺: %s' % (i + 1, detail), end='')
                try:
                    # 查找"领取"按钮
                    btn = WebDriverWait(driver, self.timeout).until(
                        lambda d: d.find_element_by_css_selector("[class='J_drawGift d-btn']"))
                except TimeoutException:
                    # 失败大多数情况下是无羊毛可褥(券妈妈平台只是简单汇总但不一定就有羊毛)
                    print(' 领取失败, TimeoutException ')
                else:
                    try:
                        # 输出羊毛战绩
                        items = WebDriverWait(driver, self.timeout).until(
                            lambda d: d.find_elements_by_css_selector("[class='d-item']"))
                        for item in items:
                            item_type = item.find_element_by_css_selector("[class='d-type']").text
                            item_num = item.find_element_by_css_selector("[class='d-num']").text
                            if item_type == '京豆': self.jing_dou += item_num
                            print(' {}{} '.format(item_type, item_num), end='')
                    except:
                        # 此处异常不太重要, 忽略
                        pass
                    finally:
                        btn.click()
                        print(' 领取成功')

            # 以下附加功能可选
            self._print_jing_dou()
            self._un_subscribe(driver)
            self._finance_sign(driver)

    def _print_jing_dou(self):
        print('O(∩_∩)O哈哈~, 共褥到了{}个京豆,相当于RMB{}元', self.jing_dou, self.jing_dou / 100)

    def _un_subscribe(self, driver):
        """批量取消店铺关注"""

        # 进入关注店铺
        subscribe_shop = 'https://t.jd.com/vender/followVenderList.action'
        driver.get(subscribe_shop)

        try:
            # 批量操作
            batch_btn = WebDriverWait(driver, self.timeout).until(
                lambda d: d.find_element_by_xpath('//*[@id="main"]/div/div[2]/div[1]/div[2]/div[2]/div/a'))
            batch_btn.click()
            # 全选店铺
            all_btn = WebDriverWait(driver, self.timeout).until(
                lambda d: d.find_element_by_xpath('//*[@id="main"]/div/div[2]/div[1]/div[2]/div[2]/div/div/span[1]'))
            all_btn.click()
            # 取消关注
            cancel_btn = WebDriverWait(driver, self.timeout).until(
                lambda d: d.find_element_by_xpath('//*[@id="main"]/div/div[2]/div[1]/div[2]/div[2]/div/div/span[2]'))
            cancel_btn.click()
            # 弹框确认
            confirm_btn = WebDriverWait(driver, self.timeout).until(
                lambda d: d.find_element_by_xpath("/html/body/div[7]/div[3]/a[1]"))
        except TimeoutException:
            print(' 批量取关店铺失败, TimeoutException ')
        else:
            confirm_btn.click()
            print(' 已批量取消关注店铺')

    def _finance_sign(self, driver):
        """京东金融签到领钢镚"""

        # 进入京东金融
        jr_login = 'https://jr.jd.com/'
        driver.get(jr_login)

        try:
            # 点击签到按钮
            sign_btn = WebDriverWait(driver, self.timeout).until(
                lambda d: d.find_element_by_xpath('//*[@id="primeWrap"]/div[1]/div[3]/div[1]/a'))
        except TimeoutException:
            print(' 京东金融签到失败, TimeoutException ')
        else:
            sign_btn.click()
            print(' 京东金融签到成功')


if __name__ == '__main__':
    qmm = QMM(sleep=3, months='7-8', days='16-31')
    qmm.start()

(左右滑动即可查看完整代码)

auth.py

from selenium.webdriver.support.wait import WebDriverWait


# QQ授权登录, 使用前提是QQ客户端在线
def qq(driver, timeout=3):
    # 切换到最新打开的窗口
    window_handles = driver.window_handles
    driver.switch_to.window(window_handles[-1])

    print('Auth QQ: ', driver.title)

    # 切换iframe
    i_frame = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_id('ptlogin_iframe'))
    driver.switch_to.frame(i_frame)

    # 点击头像进行授权登录
    login = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//*[@id="qlogin_list"]/a[1]'))
    login.click()

(左右滑动即可查看完整代码)

小小的总结

该功能还能继续完善一下的:

  1. 加入每日定时功能

  2. 扩展登录京东方式

  3. 多线程褥羊毛(需求不大)

  4. Appium抓取手机店铺主页

最后再小声BB一下

对于这次拼多多薅羊毛漏洞问题,各位看官,你觉得拼多多该全责埋单,还是给予补偿来修复已经被扩大到200亿级的漏洞呢?

不妨留个言讨论讨论。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Gw6cO5ZorE
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/28095
 
763 次点击