Python 爬虫实战—盘搜搜

近期公司给了个任务:根据关键搜索百度网盘共享文件并下载。

琢磨了几天写下了一段简单的demo代码,后期优化没有处理。

主要的思路:(1)根据关键字爬取盘搜搜的相关信息

      (2)解析并获取盘搜搜跳转到百度网盘的URL地址

      (3)解析百度网盘获取真实下载URL然后下载文件

本来下了一段ip代理处理的, 可惜免费爬取的IP时效性差基本上用不了,所以下面给出的是没有ip代理demo

然而没有ip代理处理的话, 下载不到几个文件ip就被封了。所以下面的代码仅供学习。

# -*- coding=utf-8 -*-
import random
import time
import requests
import os
import re
import urllib
import json
import string
import threading
from lxml import etree
from urllib import request, parse

def get_UserAgent():
    ‘‘‘
        返回一个随机的请求头 headers
    ‘‘‘
    USER_AGENTS = [
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
        "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
        "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
        "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
        "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
        "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
        "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
        "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
        "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
        "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
        "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
        "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
        "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
    ]
    UserAgent = random.choice(USER_AGENTS)
    headers = {‘User-Agent‘: UserAgent}
    return headers

def filterType(filename):
    ‘‘‘
    返回文件类型
    ‘‘‘
    filter_type = [‘.zip‘, ‘.pdf‘, ‘.doc‘, ‘.docx‘,
                   ‘.xls‘, ‘.xlsx‘, ‘.png‘, ‘.img‘, ‘.rar‘, ‘.txt‘]
    IsExist = ‘‘
    if filename != ‘‘:
        for item in filter_type:
            if filename.find(item) != -1:
                IsExist = item
                break
    return IsExist

def save_file(downloadUrl, saveFilePath):
    ‘‘‘
    文件下载1
    ‘‘‘
    print(‘文件开始下载并保存...‘)
    try:
        header_dict = get_UserAgent()
        with requests.get(downloadUrl, headers=header_dict, timeout=6, stream=True) as web:
            print(web.status_code)
            # 为保险起见使用二进制写文件模式,防止编码错误
            with open(saveFilePath, ‘wb‘) as outfile:
                for chunk in web.iter_content(chunk_size=1024):
                    outfile.write(chunk)
        print(‘文件下载完成...‘)
    except Exception as ex:
        print(ex)

def save_file_retrieve(downloadUrl, saveFileName):
    ‘‘‘‘‘
    文件下载2
    ‘‘‘
    local = os.path.join(‘D://downLoad//‘, saveFileName)
    request.urlretrieve(downloadUrl, local, Schedule)

def Schedule(a, b, c):
    ‘‘‘‘‘
    a:已经下载的数据块
    b:数据块的大小
    c:远程文件的大小
   ‘‘‘
    per = 100.0 * a * b / c
    if per > 100:
        per = 100
    print(‘%.2f%%‘ % per)

def get_file(downloadUrl, saveFilePath):
    ‘‘‘
    文件下载3
    ‘‘‘
    try:
        u = request.urlopen(downloadUrl)
        print(‘文件开始下载并保存...‘)
        block_sz = 8192
        with open(saveFilePath, ‘wb‘) as f:
            while True:
                buffer = u.read(block_sz)
                if buffer:
                    f.write(buffer)
                else:
                    break
        print(‘文件下载完成...‘)
    except urllib.error.HTTPError:
        # 碰到了匹配但不存在的文件时,提示并返回
        print(downloadUrl, "url file not found")
    except IOError:
        print(IOError.message)

def getAll_contentForJs(html, re_str):
    ‘‘‘
          获取js里面yunData数据,返回yunData字符串
     html: html代码
     re_str: 正则表达式
    ‘‘‘
    #res_str = r‘yunData.setData\({(.*?)}\)‘
    my_js = re.findall(re_str, html, re.S | re.M)
    jsData = my_js
    return jsData

def getAll_contentFosXpath(html, myxpath):
    ‘‘‘
          获取页面上指定内容
     html: html代码
     myxpath: xpath语法
    ‘‘‘
    myHtml = etree.HTML(html)
    mydata = myHtml.xpath(myxpath)
    return mydata

def get_postUrl(Jsparams):
    ‘‘‘
            拼接请求百度网盘真实下载地址post的url地址
    ‘‘‘
    urlstr = ‘https://pan.baidu.com/api/sharedownload?‘
    params = json.loads(Jsparams)
    urlstr += ‘sign=‘ + str(params.get(‘sign‘)) + ‘‘
    urlstr += ‘&timestamp=‘ + str(params.get(‘timestamp‘)) + ‘‘
    urlstr += ‘&bdstoken=‘ + str(params.get(‘bdstoken‘)) + ‘‘
    urlstr += ‘&channel=chunlei‘
    urlstr += ‘&clienttype=0‘
    urlstr += ‘&web=1‘
    urlstr += ‘&app_id=250528‘
    return urlstr

def get_postData(Jsparams):
    ‘‘‘
          拼接请求百度网盘真实下载地址post的请求参数
    ‘‘‘
    postdata = {}
    params = json.loads(Jsparams)
    postdata["encrypt"] = 0
    postdata["product"] = "share"
    postdata["uk"] = str(params.get("uk"))
    postdata["primaryid"] = str(params.get("shareid"))
    postdata["fid_list"] = "[" +         str(params[‘file_list‘][‘list‘][0].get(‘fs_id‘)) + "]"
    return postdata

def get_downLoad(Jsparams):
    ‘‘‘
          发送post请求获取真实下载地址
    ‘‘‘
    print(‘发送post请求获取真实下载路径...‘)
    try:
        header_dict = get_UserAgent()
        params = parse.urlencode(get_postData(
            Jsparams)).encode(encoding=‘UTF8‘)
        req = request.Request(url=get_postUrl(Jsparams),
                              data=params, headers=header_dict, method="POST")
        resp = request.urlopen(req)
        resp = resp.read().decode(encoding=‘utf-8‘)
        return resp
    except Exception as ex:
        print(ex)

def get_html(urlLink, headers):
    ‘‘‘
    获取页面代码html,  同IP多次请求会出现超时现象。
    ‘‘‘
    try:
        response = requests.get(
            url=urlLink, headers=headers, timeout=60)
        response.encoding = response.apparent_encoding
        if response.status_code == 200:
            return response.text
    except urllib.request.URLError as e:
        print(‘URLError! The bad Msg is %s‘ % e)
        return None
    except urllib.request.HTTPError as e:
        print(‘HTTPError! The bad Msg is %s‘ % e)
        return None
    except Exception as e:
        print(‘Unknown Errors! The bad Msg is %s ‘ % e)
        return None

def get_redirects(urlLink, headers):
    try:
        response = requests.get(
            url=urlLink, headers=headers, timeout=60, allow_redirects=False)
        return response.headers[‘Location‘]
    except urllib.request.URLError as e:
        print(‘URLError! The bad Msg is %s‘ % e)
        return None
    except urllib.request.HTTPError as e:
        print(‘HTTPError! The bad Msg is %s‘ % e)
        return None
    except Exception as e:
        print(‘Unknown Errors! The bad Msg is %s ‘ % e)
        return None

def baiDuShare(bdUrl):
    try:
        print(‘解析盘搜搜详情页‘)
        header_dict = get_UserAgent()
        shareHtml = get_html(bdUrl, header_dict)
        if shareHtml != None:
            ‘‘‘
            解析网站数据获取百度网盘共享文件URL
            ‘‘‘
            # 共享文件名称
            share_file = getAll_contentFosXpath(
                shareHtml, ‘//*[@id="con"]/div/div[1]/h1‘)
            fileName = share_file[0].text
            # 共享文件大小
            share_size = getAll_contentForJs(
                shareHtml, ‘<dd>文件大小:(.*?)MB</dd>‘)
            # 百度网盘共享地址
            share_link = getAll_contentForJs(
                shareHtml, ‘a=go&url=(.*?)&t=‘)
            share_url = ‘http://to.pansoso.com/?a=to&url=‘ +                 share_link[0]
            panRedirects = get_redirects(share_url, header_dict)
            if panRedirects != None:
                # 获取文件对应类型
                print(panRedirects)
                print(fileName)
                FirtHtml = get_html(panRedirects, header_dict)
                share_type = filterType(fileName)
                MyJS = getAll_contentForJs(
                    FirtHtml, r‘yunData.setData\({(.*?)}\)‘)
                StrMyJS = ‘{‘ + MyJS[0] + ‘}‘
                DownLink = json.loads(get_downLoad(StrMyJS))
                print(DownLink[‘list‘][0].get(‘dlink‘))
                save_file(DownLink[‘list‘][0].get(‘dlink‘),
                          ‘D://downLoad//‘ + str(fileName).replace(share_type, ‘‘) + share_type)  # 有些文件后缀不在标题的最后,所以将它替换为空再在最后加上文件后缀
            else:
                print(‘百度共享盘解析失败‘)
        else:
            print(‘盘搜搜详情页失败‘)
    except Exception as e:
        print(‘Unknown Errors! The bad Msg is %s ‘ % e)
        return None

if __name__ == ‘__main__‘:
    headers = get_UserAgent()  # 定制请求头
    targeturl = ‘http://www.pansoso.com‘
    headers["Host"] = "www.pansoso.com"
    headers["Accept-Language"] = "zh-CN,zh;q=0.9"
    searchStr = input(‘请输入关键字:‘)
    searchUrl = ‘http://www.pansoso.com/zh/%s‘ % searchStr
    searchUrl = request.quote(searchUrl, safe=string.printable)
    print(‘开始搜索【%s】网盘共享: %s‘ % (searchStr, searchUrl))
    try:
        time.sleep(random.random() * 10)
        panSosoHtml = get_html(searchUrl, headers)
        if panSosoHtml != None:
            panSosoTitle = getAll_contentFosXpath(
                panSosoHtml, ‘//div[@id="content"]/div[@class="pss"]/h2/a‘)
            baiduthreads = []
            for titleItem in panSosoTitle:
                # 筛选出文件类型以及关键字匹配的 共享文件
                if filterType(titleItem.text) != ‘‘ and str(titleItem.text).find(searchStr) != -1:
                    print(targeturl + titleItem.attrib[‘href‘])
                    Urlparam = targeturl + titleItem.attrib[‘href‘]
                    t = threading.Thread(
                        target=baiDuShare, args=(Urlparam,))
                    baiduthreads.append(t)
            for s in baiduthreads:  # 开启多线程爬取
                s.start()
                time.sleep(random.random() * 10)
            for e in baiduthreads:  # 等待所有线程结束
                e.join()
        else:
            print(‘请求失败‘)
    except Exception as e:
        print(‘Unknown Errors! The bad Msg is %s ‘ % e)

原文地址:https://www.cnblogs.com/witeem/p/9068351.html

时间: 2024-10-03 06:06:28

Python 爬虫实战—盘搜搜的相关文章

Python爬虫实战(2):爬取京东商品列表

1,引言 在上一篇<Python爬虫实战:爬取Drupal论坛帖子列表>,爬取了一个用Drupal做的论坛,是静态页面,抓取比较容易,即使直接解析html源文件都可以抓取到需要的内容.相反,JavaScript实现的动态网页内容,无法从html源代码抓取需要的内容,必须先执行JavaScript. 我们在<Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容>一文已经成功检验了动态网页内容的抓取方法,本文将实验程序进行改写,使用开源Python爬虫

python爬虫实战——5分钟做个图片自动下载器

python爬虫实战--图片自动下载器 制作爬虫的基本步骤 顺便通过这个小例子,可以掌握一些有关制作爬虫的基本的步骤. 一般来说,制作一个爬虫需要分以下几个步骤: 分析需求(对,需求分析非常重要,不要告诉我你老师没教你) 分析网页源代码,配合F12(没有F12那么乱的网页源代码,你想看死我?) 编写正则表达式或者XPath表达式(就是前面说的那个神器) 正式编写python爬虫代码 效果 运行: 恩,让我输入关键词,让我想想,输入什么好呢?好像有点暴露爱好了. 回车 好像开始下载了!好赞!,我看

【图文详解】python爬虫实战——5分钟做个图片自动下载器

python爬虫实战--图片自动下载器 之前介绍了那么多基本知识[Python爬虫]入门知识,大家也估计手痒了.想要实际做个小东西来看看,毕竟: talk is cheap show me the code! 制作爬虫的基本步骤 顺便通过这个小例子,可以掌握一些有关制作爬虫的基本的步骤. 一般来说,制作一个爬虫需要分以下几个步骤: 1. 分析需求(对,需求分析非常重要,不要告诉我你老师没教你) 2. 分析网页源代码,配合F12(没有F12那么乱的网页源代码,你想看死我?) 3. 编写正则表达式或

Python爬虫实战(4):豆瓣小组话题数据采集—动态网页

1, 引言 注释:上一篇<Python爬虫实战(3):安居客房产经纪人信息采集>,访问的网页是静态网页,有朋友模仿那个实战来采集动态加载豆瓣小组的网页,结果不成功.本篇是针对动态网页的数据采集编程实战. Python开源网络爬虫项目启动之初,我们就把网络爬虫分成两类:即时爬虫和收割式网络爬虫.为了适应各种应用场景,GooSeeker的整个网络爬虫产品线包含了四类产品,如下图所示: 本实战是上图中的"独立python爬虫"的一个实例,以采集豆瓣小组讨论话题(https://w

Python爬虫实战七之计算大学本学期绩点

大家好,本次为大家带来的项目是计算大学本学期绩点.首先说明的是,博主来自山东大学,有属于个人的学生成绩管理系统,需要学号密码才可以登录,不过可能广大读者没有这个学号密码,不能实际进行操作,所以最主要的还是获取它的原理.最主要的是了解cookie的相关操作. 本篇目标 1.模拟登录学生成绩管理系统 2.抓取本学期成绩界面 3.计算打印本学期成绩 1.URL的获取 恩,博主来自山东大学~ 先贴一个URL,让大家知道我们学校学生信息系统的网站构架,主页是 http://jwxt.sdu.edu.cn:

Python爬虫实战四之抓取淘宝MM照片

福利啊福利,本次为大家带来的项目是抓取淘宝MM照片并保存起来,大家有没有很激动呢? 最新动态 更新时间:2015/8/2 最近好多读者反映代码已经不能用了,原因是淘宝索引页的MM链接改了.网站改版了,URL的索引已经和之前的不一样了,之前可以直接跳转到每个MM的个性域名,现在中间加了一个跳转页,本以为可以通过这个页面然后跳转到原来的个性域名,而经过一番折腾发现,这个跳转页中的内容是JS动态生成的,所以不能用Urllib库来直接抓取了,本篇就只提供学习思路,代码不能继续用了. 之后博主会利用其它方

Python爬虫实战二之爬取百度贴吧帖子

大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 前言 亲爱的们,教程比较旧了,百度贴吧页面可能改版,可能代码不好使,八成是正则表达式那儿匹配不到了,请更改一下正则,当然最主要的还是帮助大家理解思路. 2016/12/2 本篇目标 1.对百度贴吧的任意帖子进行抓取 2.指定是否只抓取楼主发帖内容 3.将抓取到的内容分析并保存到文件 1.URL格式的确定 首先,我们先观察一下百度贴吧的任意一个帖子. 比如:ht

Python爬虫实战---抓取图书馆借阅信息

原创作品,引用请表明出处:Python爬虫实战---抓取图书馆借阅信息 前段时间在图书馆借了很多书,借得多了就容易忘记每本书的应还日期,老是担心自己会违约,影响日后借书,而自己又懒得总是登录到学校图书馆借阅系统查看,于是就打算写一个爬虫来抓取自己的借阅信息,把每本书的应还日期给爬下来,并写入txt文件,这样每次忘了就可以打开该txt文件查看,每次借阅信息改变了,只要再重新运行一遍该程序,原txt文件就会被新文件覆盖,里面的内容得到更新. 用到的技术: Python版本是 2.7 ,同时用到了ur

转 Python爬虫实战二之爬取百度贴吧帖子

静觅 » Python爬虫实战二之爬取百度贴吧帖子 大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 本篇目标 1.对百度贴吧的任意帖子进行抓取 2.指定是否只抓取楼主发帖内容 3.将抓取到的内容分析并保存到文件