标签归档:Python爬虫

Python 一个超快的公共情报搜集爬虫

Photon是一个由s0md3v开源的情报搜集爬虫,其主要功能有:

1.爬取链接(内链、外链)。
2.爬取带参数的链接,如(pythondict.com/test?id=2)。
3.文件(pdf, png, xml)。
4.密钥(在前端代码中不小心被释放出来的)。
5.js文件和Endpoint(spring中比较重要的监视器)
6.匹配自定义正则表达式的字符串。
7.子域名和DNS相关数据。

你可以用它来干很多事,比如爬图片、找漏洞、找子域名、爬数据等等。而且提取出来的数据格式非常整洁:

不仅如此,它甚至支持json格式 ,仅需要在输入命令的时候加上json参数:

python photon.py -u "http://example.com" --export=json

为什么能用来做情报搜集呢?耐心往后看哦。

1.下载安装

你可以上photon的github下载完整项目:
https://github.com/s0md3v/Photon

或者关注下方Python实用宝典公众号在后台回复photon获得国内网盘下载地址。下载后解压到你想要使用的地方。如果你还没有安装Python,建议阅读这篇文章:超详细Python安装指南,进行Python的安装。

安装完Python后,打开CMD(windows)/Terminal(macOS),下面简称这两种为终端,进入你刚解压的文件夹,然后输入以下命令安装Photon的依赖:

pip install -r requirements.txt

如图所示:

2.简单使用

注意,使用的时候要在Photon文件夹下。比如我们随便提取一个网站的URL试一下,在终端输入以下命令:

python photon.py -u https://bk.tencent.com/

结果如下:

它会在当前目录下产生一个你测试的域名的文件夹,比如在我这里是 bk.tencent.com:

嘻嘻,让我们看看里面有什么东西,有没有程序员留下的小彩蛋,打开external.txt,这是该网站的外链的存放位置。可以看到,这里不仅仅是只有网站页面,连CDN文件地址都会放在这里,所以external可能是个藏宝哦。

还能一下找出该网站上链接的全部开源项目:

3.扩展

这个项目的价值,不仅在于能够快速拉取你想要得到的数据,还在于能够构建一个牛逼轰轰的情报系统(如果你技术够强的话)。因为它是能不断延伸下去的,比如从外链出发,你能找到很多和这个网站相关的讯息:

相比于搜索引擎搜索的结果,实际上这些信息更符合情报要求。因为不是所有的信息都能在搜索引擎搜索得到,而通过这个Photon,你可以顺藤摸瓜找到那些隐藏在互联网世界的它们。试想一下,如果你搜集了很多这样的网站…然后用正则表达式搭建一个属于你自己的搜索引擎,这样的感觉是不是很棒?

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 爬取“微博树洞”详细教程

最近要做一个关于自动从微博等短文本数据中判断人是否有自杀倾向的项目,在这之前需要先收集许多具有自杀倾向的人发的微博或短文本数据作为训练集。

其实这样的数据是挺难找的,尤其是对于我这种需求量比较大的项目。不过好在最后发现了突破口:“微博树洞”。“微博树洞”是指宣告了自杀行为的过世的人的微博,其留言区成为成千上万的抑郁症或是绝望的人的归属,在其下方发布许多负能量甚至是寻死的宣言。

比如走饭的微博:

1.找到微博评论数据接口

微博评论的数据接口有两种,一种是手机版、一种是PC版。手机版能爬到的数据仅仅只有十五页,因此我们从PC版入手,先来看看PC版的接口怎么找,长啥样儿。

首先,在当前微博的页面右键—检查(F12)打开开发者工具,然后按照下图的步骤进行操作(选择NetWork—选择XHR—随便点击另一个评论页—查看右侧新增的请求):

然后我们看新增的请求,你会发现在Preview中能看到格式化后的数据,而且里面有个html,仔细观察这个html你会发现这个就是评论列表的数据。我们仅需要将这个html解析出来即可。

再看看get请求的URL:

https://weibo.com/aj/v6/comment/big?ajwvr=6&id=3424883176420210&page=2&__rnd=1573219876141

ajwvr是一个固定值为6、id是指想要爬取评论的微博id、page是指第几页评论、_rnd是请求时的毫秒级时间戳。

不过微博是要求登录才能看更多评论的,因此我们需要先访问微博,拿到cookie的值才能开始爬。

2.编写爬虫

关注文章最下方的Python实用宝典,回复微博评论爬虫即可获得本项目的完整源代码。

设定四个参数:

    params = {
        'ajwvr': 6,
        'id': '3424883176420210',
        'page': 1,
        '_rnd': int(round(time.time() * 1000))
    } 

设定cookie:

headers = { 
    'X-Requested-With': 'XMLHttpRequest', 
    'Cookie': '你的微博cookie',
} 

发送请求并解析数据

    URL = 'https://weibo.com/aj/v6/comment/big'

    for num in range(1,51,1):
        print(f'============== 正在爬取第 {num} 页 ====================')
        params['page'] = num
        params['_rnd'] = int(round(time.time() * 1000))
        resp = requests.get(URL, params=params, headers=headers)
        resp = json.loads(resp.text) 

解析这串HTML中我们所需要的数据,这里用到了XPATH,如果你还不了解XPATH,可以看这篇文章: 学爬虫利器XPath,看这一篇就够了

         if resp['code'] == '100000':
            html = resp['data']['html']
            html = etree.HTML(html)
            data = html.xpath('//div[@node-type="comment_list"]')
            for i in data:
                # 评论人昵称
                nick_name = i.xpath('.//div[@class="WB_text"]/a[1]/text()')
                # 评论内容
                text = i.xpath('.//div[@class="WB_text"]')
                text = [i.xpath('string(.)') for i in text]
                # 头像地址
                pic_url = i.xpath('.//div[@class="WB_face W_fl"]/a/img/@src')
                print(len(nick_name),len(text),len(pic_url))
                write_comment([i.strip() for i in text], pic_url, nick_name) 

其中写入文件的函数和下载图片的函数如下:

# 下载图片
def download_pic(url, nick_name):
    if not url:
        return
    if not os.path.exists(pic_file_path):
        os.mkdir(pic_file_path)
    resp = requests.get(url)
    if resp.status_code == 200:
        with open(pic_file_path + f'/{nick_name}.jpg', 'wb') as f:
            f.write(resp.content)

# 写入留言内容
def write_comment(comment, pic_url, nick_name):
    f = open('comment.txt', 'a', encoding='utf-8')
    for index, i in enumerate(comment):
        if ':' not in i and '回复' not in i and i != '':
            # 去除评论的评论
            w_comment = i.strip().replace(':', '').replace('\n', '')
            # 写入评论
            f.write(w_comment.replace('等人', '').replace('图片评论', '')+'\n')
            # 获得头像
            download_pic(pic_url[index], nick_name[index]) 

以上就是我们所用到的代码。在公众号后台回复 微博评论爬虫 即可下载完整源代码(附手机版爬虫)。

3.定时爬虫

尽管如此,我们得到的数据还是不够,PC版的微博评论页面也仅仅支持爬到第五十页,第五十一页后就拿不到数据了,如图:

不过,走饭这个微博真的很多人回复,一天的数据就差不多50页了,我们可以通过每天定时爬50页来获取数据。linux系统可以使用crontab定时脚本实现,windows系统可以通过计划任务实现,这里讲讲crontab实现方法。

假设你的Python存放在/usr/bin/且将脚本命名为weibo.py 存放在home中,在终端输入crontab -e后,在最后面增加上这一条语句即可:

0 0 * * * /usr/bin/python /home/weibo.py

在公众号后台回复 微博评论爬虫 即可下载本文完整源代码(附手机版爬虫) 。

如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 批量下载网易云音乐歌单

网易云音乐有非常优秀的分享氛围,有许多好听的歌单,不过有时候我们想要下载这些歌单到自己的MP4或可移动存储设备却非常麻烦:要么是有VIP但歌单歌曲太多、一个一个下载非常麻烦,要么是没VIP无法下载一些歌曲。今天给大家推荐一种基于Python的下载方法,可以批量免VIP下载歌单音乐

作者直接将其用 wxPython做成了一个exe程序,如果你想直接使用但是却上不了github的话,请扫描关注最下方Python实用宝典公众号二维码,回复 网易云音乐下载 获得程序和源代码。开源项目地址: 网易云音乐歌曲批量下载,免VIP【支持歌单,排名榜】

1.爬取原理

1.1 通过接口下载歌曲

我们知道,可在线播放的音乐大部分存在可以直接访问下载音乐的链接,这就是它的真实外链地址。而网易云音乐的真实外链地址是:

https://music.163.com/song/media/outer/url?id=%E6%AD%8C%E6%9B%B2id.mp3&_=1

只要通过获得歌单的所有歌曲ID,然后将其替换到这个真实外链地址中,我们就能够实现歌曲的批量下载。这份开源代码的作者没有使用异步的形式进行下载,如果你想要下载的歌单歌曲非常多的话,建议你将其改成异步的形式,具体的教程可见我们之前的文章:Python 异步批量下载

1.2 获得歌单所有的歌曲ID

可以随意打开一个歌单,比如网 易 10w 评 论 的 热 歌. 使用开发者工具,可以非常轻易地定位到歌单里的音乐的链接:

而这个链接的后面 id=xxxxxx 就是这首歌曲的id,我们仅需要定位到这些链接的css,使用beautifulsoup即可获得它们的id。看看作者是怎么写的:

2. 程序使用方法

将你想要下载的歌单地址放入这个exe程序即可:

手机版网易云音乐,仅需要进入歌单,然后点击分享按钮,就可复制链接获得歌单地址:

然后把这个地址放入程序中即可开始批量下载啦,怎么样,是不是非常方便的工具?感谢原作者的分享,给它点个star吧!

文章到此就结束啦,如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!

音乐相关教程:

Python 批量下载网易云音乐歌单

Python 制作音乐高潮副歌提取器

Python Django快速开发音乐高潮提取网(1)

Python Django快速开发音乐高潮提取网(2)

Python Django快速开发音乐高潮提取网(3)

Python 超方便超快速剪辑音乐

Python 提取音乐频谱并可视化

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 反编译调用有道翻译(附完整代码)

网易有道翻译是一款非常优秀的产品,他们的神经网络翻译真的挺无敌。无奈有道客户端实在是太难用了,而且在某些具体场景(比如对网站进行批量翻译)无法使用,而有道的云服务又特别的贵,一般人是无法支付得起的。

然而理论上而言,所有看得见的东西都是爬得到的,有道翻译接口也一样。为了祖国未来花朵(咸鱼) 的发展,今天就来给大家介绍一下如何用 Python超简单快速地调用有道翻译得到翻译结果 。此外,本教程仅供学习哦。

如果你懒得看教程,只想要拿到源代码,请关注Python实用宝典公众号并回复:“Python有道接口” 。

1.找到翻译相关接口

打开 fanyi.youdao.com 随便输入一个单词进行翻译,使用开发者工具(空白处右键检查或F12)查看请求数据。

可以看到,请求的接口是:
http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule

开发者工具往下拉,查看Form Data得到请求的body是:

  1. i: 你好
  2. from: AUTO
  3. to: AUTO
  4. smartresult: dict
  5. client: fanyideskweb
  6. salt: 15707931034929
  7. sign: 99d0fc48506346afc40e36d5648cc320
  8. ts: 1570793103492
  9. bv: ca3dedaa9d15daa003dbdaaa991540d1
  10. doctype: json
  11. version: 2.1
  12. keyfrom: fanyi.web
  13. action: FY_BY_REALTlME

2.解析请求body内容

显然,以上body内容中,i 是需要翻译的文本,from是原文语言,to是翻译语言。我们其他的参数只需要设置为一致的即可。现在需要解决这几个参数:salt, sign, bv,ts.

ts从格式上看就知道是时间戳,而且ts和salt内容很接近,且只差了一位,可以合理猜测,salt就是ts+1位随机数。

接下来就差sign和bv,这两个值看起来非常像MD5,不过不确定是什么参数的MD5,因此需要阅读前端源代码。

在performance中录制,重新请求接口,找到翻译接口的前端代码(fanyi.min.js).然后搜索我们的关键词sign或者bv. 使用debug工具查看值的流动。

从这里我们可以知道,bv 即浏览器头部信息MD5的值,我的浏览器头部是这样的: “5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36”

实际上在请求接口的时候随便用什么头部都能过这个校验,只要符合标准就行。

最后一个未知参数是sign. 同样,我们打开debug模式,输入信息,就可以得到其值了。

很显然,sign由n.md5(“fanyideskweb” + e + i + “n%A-rKaT5fb[Gy?;N5@Tj”)组成,而e根据debug显示的结果,就是我们需要翻译的信息,而i就是salt. 因此4个参数我们全部成功反编译!

3. 用Python调用接口进行翻译

我们只需要伪造请求的body,向接口发送post请求即可得到翻译结果。比如,ts是13位时间戳,在Python中可以使用time.time()*1000获得:

ts = str(int(time.time()*1000))

salt是ts+一位随机数,太简单了:

salt = ts + str(random.randint(0, 9))

bv是浏览器User-Agent,需要进行MD5计算,我们新建一个MD5函数,将字符串传入函数获得MD5。

def get_md5(string):
    string = string.encode('utf-8')
    md5 = hashlib.md5(string).hexdigest()
    return md5
bv = get_md5("5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")

sign是四个字符串组成后进行MD5的结果:

sign = get_md5("fanyideskweb" + context + salt + "n%A-rKaT5fb[Gy?;N5@Tj") 

这样,我们获得了所有需要用到的参数,集合在一起后发送post请求。

试一下效果:

print(translation('你好')) 

成功得到接口返回的翻译结果:

(base) F:\push\20191011>python YouDaoSpider.py
hello 

关注下方的公众号,回复 “Python有道接口“即可获得全部源代码。

文章到此就结束啦,如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

爬虫工具篇 – 必会用的 6 款 Chrome 插件

在日常 PC 端的爬虫过程工作中,Chrome 浏览器是我们常用的一款工具

鉴于 Chrome 浏览器的强大,Chrome 网上应用商店很多强大的插件可以帮助我们快速高效地进行数据爬虫

今天推荐的 6 款 Chrome 插件,可以大大提升我们的爬虫效率。

EditThisCookie  

EditThisCookie 是一个 Cookie 管理器,可以很方便的添加,删除,编辑,搜索,锁定和屏蔽 Cookies。

可以将登录后的 Cookies 先保存到本地,借助 cookielib ,直接爬取登录后的数据。

避免了抓包和模拟登录,帮助我们快速地进行爬虫

Web Scraper

Web Scraper 是一款免费的、适用于任何人,包含没有任何编程基础的爬虫工具

操作简单,只需要鼠标点击和简单的配置,就能快速的爬取 Web 端的数据。

它支持复杂的网站结构,数据支持文本、连接、数据块、下拉加载数据块等各种数据类型。

此外,还能将爬取的数据导出到 CSV 文件中。

Xpath Helper

Xpath Helper 是一种结构化网页元素选择器,支持列表和单节点数据获取,

它可以快速地定位网页元素。

对比 Beautiful Soup,由于 Xpath 网页元素查找性能更有优势;Xpath 相比正则表达式编写起来更方便。

编写 Xpath 之后会实时显示匹配的数目和对应的位置,方便我们判断语句是否编写正确。

Toggle JavaScript

Toggle JavaScript 插件可以用来检测当前网页哪些元素是通过 AJAX 动态加载的。

使用它可以快速在容许加载 JS 、禁止加载 JS 两种模式中切换。

User-Agent Switcher for Chrome

User-Agent Switcher for Chrome 插件可以很方便的修改浏览器的 User-Agent。

可以模拟不同的浏览器、客户端,包含 Android、IOS 去模拟请求。

对于一些特殊网站,切换 User-Agent 可以更方便地进行数据爬取。

JSON-handle

JSON-handle 是一款功能强大的JSON数据解析Chrome插件。它以简单清晰的树形图样式展现 JSON 文档,并可实时编辑。针对数据量大的场景,可以做局部选取分析。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们。有任何问题请在下方留言,我们会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 超简单爬取新浪微博数据 (高级版)

新浪微博的数据可是非常有价值的,你可以拿来数据分析、拿来做网站、甚至是*****。不过很多人由于技术限制,想要使用的时候只能使用复制粘贴这样的笨方法。没关系,现在就教大家如何批量爬取微博的数据,大大加快数据迁移速度!

我们使用到的是第三方作者开发的爬虫weiboSpider(有工具当然要用工具啦)。这里默认大家已经装好了Python,如果没有的话可以看我们之前的文章:Python详细安装指南

1. 下载项目

进入下方的网址,点击Download ZIP下载项目文件

https://github.com/dataabc/weiboSpider

或者

你有git的话可以在cmd/terminal中输入以下命令安装​

git clone https://github.com/dataabc/weiboSpider.git 

​2.安装依赖

将该项目压缩包解压后,打开你的cmd/Termianl进入该项目目录,输入以下命令:

pip install -r requirements.txt

便会开始安装项目依赖,等待其安装完成即可。

3.设置cookie

打开weibospider文件夹下的weibospider.py文件,将”your cookie”替换成爬虫微博的cookie,具体替换位置大约在weibospider.py文件的22行左右。cookie获取方法:

3.1 登录微博

3.2 按F12键或者右键页面空白处—检查,打开开发者工具

3.3 选择network — 按F5刷新一下 — 选择第一个文件 — 在右边窗口找到cookie

然后替换大约在weibospider.py文件的22行左右的cookie,如图所示:

替换前:

替换后:

4.设置要爬的用户user_id

4.1 获取user_id

点开你希望爬取的用户主页,然后查看此时的url:

你会发现有一串数字在链接中,这个就是我们要用到的userID, 复制即可。

4.2 设置要爬取的user_id

打开config.json文件,你会看到如下内容:

{
    "user_id_list": ["1669879400"],
    "filter": 1,
    "since_date": "2018-01-01",
    "write_mode": ["csv", "txt"],
    "pic_download": 1,
    "video_download": 1,
    "cookie": "your cookie",
    "mysql_config": {
        "host": "localhost",
        "port": 3306,
        "user": "root",
        "password": "123456",
        "charset": "utf8mb4"
    }
}

下面讲解每个参数的含义与设置方法。

设置user_id_list
user_id_list是我们要爬取的微博的id,可以是一个,也可以是多个,例如:

"user_id_list": ["1223178222", "1669879400", "1729370543"],

上述代码代表我们要连续爬取user_id分别为“1223178222”、 “1669879400”、 “1729370543”的三个用户的微博。

user_id_list的值也可以是文件路径,我们可以把要爬的所有微博用户的user_id都写到txt文件里,然后把文件的位置路径赋值给user_id_list。

在txt文件中,每个user_id占一行,也可以在user_id后面加注释(可选),如用户昵称等信息,user_id和注释之间必需要有空格,文件名任意,类型为txt,位置位于本程序的同目录下,文件内容示例如下:

1223178222 胡歌
1669879400 迪丽热巴
1729370543 郭碧婷

假如文件叫user_id_list.txt,则user_id_list设置代码为:

"user_id_list": "user_id_list.txt",

如果有需要还可以设置Mysql数据和MongoDB数据写入,如果不设置的话就默认写入到txt和csv文件中。

5. 运行爬虫

打开cmd/terminal 进入该项目目录,输入:

python weibospider.py

即可开始爬取数据了,怎么样,是不是超级方便?而且你还可以自定义爬取的信息,比如微博的起始时间、是否写入数据,甚至能在它代码的基础上增加新的功能!(比如加个cookie池或者代理池之类的)

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 超简单爬取微博热搜榜数据

微博的热搜榜对于研究大众的流量有非常大的价值。今天的教程就来说说如何爬取微博的热搜榜。 热搜榜的链接是:

https://s.weibo.com/top/summary/

用浏览器浏览,发现在不登录的情况下也可以正常查看,那就简单多了。使用开发者工具(F12)查看页面逻辑,并拿到每条热搜的CSS位置,方法如下:

按照这个方法,拿到这个td标签的selector是:
pl_top_realtimehot > table > tbody > tr:nth-child(3) > td.td-02

其中nth-child(3)指的是第三个tr标签,因为这条热搜是在第三名的位置上,但是我们要爬的是所有热搜,因此:nth-child(3)可以去掉。

还要注意的是 pl_top_realtimehot 是该标签的id,id前需要加#号,最后变成:
#pl_top_realtimehot > table > tbody > tr > td.td-02

你可以自定义你想要爬的信息,这里我需要的信息是:热搜的链接及标题、热搜的热度。它们分别对应的CSS选择器是:

链接及标题:#pl_top_realtimehot > table > tbody > tr > td.td-02 > a
热度:#pl_top_realtimehot > table > tbody > tr > td.td-02 > span

值得注意的是链接及标题是在同一个地方,链接在a标签的href属性里,标题在a的文本中,用beautifulsoup有办法可以都拿到,请看后文代码。

现在这些信息的位置我们都知道了,接下来可以开始编写程序。默认你已经安装好了python,并能使用cmd的pip,如果没有的话请见这篇教程:python安装。需要用到的python的包有:

BeautifulSoup4 安装指令:

pip install beautifulsoup4

lxml解析器安装指令:

pip install lxml

lxml是python中的一个包,这个包中包含了将html文本转成xml对象的工具,可以让我们定位标签的位置。而能用来识别xml对象中这些标签的位置的包就是 Beautifulsoup4.

编写代码:

# https://s.weibo.com/top/summary/
import requests
from bs4 import BeautifulSoup

if __name__ == "__main__":
    news = []
    # 新建数组存放热搜榜
    hot_url = 'https://s.weibo.com/top/summary/'
    # 热搜榜链接
    r = requests.get(hot_url)
    # 向链接发送get请求获得页面
    soup = BeautifulSoup(r.text, 'lxml')
    # 解析页面

    urls_titles = soup.select('#pl_top_realtimehot > table > tbody > tr > td.td-02 > a')
    hotness = soup.select('#pl_top_realtimehot > table > tbody > tr > td.td-02 > span')

    for i in range(len(urls_titles)-1):
        hot_news = {}
        # 将信息保存到字典中
        hot_news['title'] = urls_titles[i+1].get_text()
        # get_text()获得a标签的文本
        hot_news['url'] = "https://s.weibo.com"+urls_titles[i]['href']
        # ['href']获得a标签的链接,并补全前缀
        hot_news['hotness'] = hotness[i].get_text()
        # 获得热度文本
        news.append(hot_news) 
        # 字典追加到数组中 
    
    print(news)

代码说明请看注释,不过这样做,我们仅仅是将结果保存到数组中,如下所示,其实不易观看,我们下面将其保存为csv文件。

Python 热搜榜爬虫
    import datetime
    today = datetime.date.today()
    f = open('./热搜榜-%s.csv'%(today), 'w', encoding='utf-8')
    for i in news:
        f.write(i['title'] + ',' + i['url'] + ','+ i['hotness'] + '\n')

效果如下,怎么样,是不是好看很多:

Python 微博热搜榜爬虫

完整代码如下:

# https://s.weibo.com/top/summary/
import requests
from bs4 import BeautifulSoup

if __name__ == "__main__":
    news = []
    # 新建数组存放热搜榜
    hot_url = 'https://s.weibo.com/top/summary/'
    # 热搜榜链接
    r = requests.get(hot_url)
    # 向链接发送get请求获得页面
    soup = BeautifulSoup(r.text, 'lxml')
    # 解析页面

    urls_titles = soup.select('#pl_top_realtimehot > table > tbody > tr > td.td-02 > a')
    hotness = soup.select('#pl_top_realtimehot > table > tbody > tr > td.td-02 > span')

    for i in range(len(urls_titles)-1):
        hot_news = {}
        # 将信息保存到字典中
        hot_news['title'] = urls_titles[i+1].get_text()
        # get_text()获得a标签的文本
        hot_news['url'] = "https://s.weibo.com"+urls_titles[i]['href']
        # ['href']获得a标签的链接,并补全前缀
        hot_news['hotness'] = hotness[i].get_text()
        # 获得热度文本
        news.append(hot_news)
        # 字典追加到数组中
    
    print(news)

    import datetime
    today = datetime.date.today()
    f = open('./热搜榜-%s.csv'%(today), 'w', encoding='utf-8')
    for i in news:
        f.write(i['title'] + ',' + i['url'] + ','+ i['hotness'] + '\n')

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

python 文件下载、大文件下载、异步批量下载 教程

按照不同的情况,Python下载文件可以分为三种:小文件下载大文件下载、批量下载

本文源代码: https://pythondict.com/download/python-file-download-source-code/

python 小文件下载

流程:使用request.get请求链接,返回的内容放置到变量r中,然后将r写入到你想放的地方。

Python小文件下载流程

以下载上述流程图为例子:

# 例1
import requests
def request_zip(url):
    r = requests.get(url) 
    # 请求链接后保存到变量r中
    with open("new/名字.png",'wb') as f:
        # r.content写入至文件
        f.write(r.content)
request_zip('https://pythondict.com/wp-content/uploads/2019/08/2019082807222049.png')

运行完毕后,它将会被保存到当前文件夹的new文件夹里。

python 大文件下载

我们在小文件下载的时候,是将文件内容暂存到变量里,大家想想,下载大文件的时候还这样做会有什么问题?

很简单,如果你的内存只有8G,结果要下载文件却有10G那么大,那就肯定无法下载成功了。而且本机软件运行占的内存也比较大,如果你的内存只有8G,实际上剩余可用的内存可能低于2G-4G. 这种情况下怎么下载大文件呢?

流式分块下载

原理:一块一块地将内存写入到文件中,以避免内存占用过大。

Python大文件下载流程

当设置了request.get(stream=True)的时候,就是启动流模式下载,典型特征:在r变量的content被调用的时候才会启动下载。代码如下:

# 例2
import requests
def request_big_data(url):
    name = url.split('/')[-1]
    # 获取文件名
    r = requests.get(url, stream=True)
    # stream=True 设置为流读取
    with open("new/"+str(name), "wb") as pdf:
        for chunk in r.iter_content(chunk_size=1024):
            # 每1024个字节为一块进行读取
            if chunk:
                # 如果chunk不为空
                pdf.write(chunk)
request_big_data(url="https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe")

Python 批量文件下载

所谓批量下载,当然不是一个一个文件的下载了,比如说我们要下载百度图片,如果一个一个下载会出现两种负面情况:

  1. 如果某个请求堵塞,整个队列都会被堵塞
  2. 如果是小文件,单线程下载太慢

我们的解决方案是使用异步策略。如果你会用scrapy框架,那就轻松许多了,因为它结合了twisted异步驱动架构,根本不需要你自己写异步。不过我们python实用宝典讲的可是教程,还是跟大家说一下怎么实现异步下载:

我们需要使用到两个包,一个是asyncio、一个是aiohttp. asyncio是Python3的原装,但是aiohttp则需要各位使用cmd/Terminal打开,输入以下命令安装:

pip install aiohttp

注意asyncio是单进程并发,不是多线程,也不是多进程,是协程。单纯是在一个进程里面异步(切来切去运行),切换的地方用await标记,能够切换的函数用async标记。比如下载异步批量下载两个图片的代码如下:

# 例3
import aiohttp
import asyncio
import time
async def job(session, url):
    # 声明为异步函数
    name = url.split('/')[-1]
    # 获得名字
    img = await session.get(url)
    # 触发到await就切换,等待get到数据
    imgcode = await img.read()
    # 读取内容
    with open("new/"+str(name),'wb') as f:
        # 写入至文件
        f.write(imgcode)
    return str(url)

async def main(loop, URL):
    async with aiohttp.ClientSession() as session:
        # 建立会话session
        tasks = [loop.create_task(job(session, URL[_])) for _ in range(2)]
        # 建立所有任务
        finished, unfinished = await asyncio.wait(tasks)
        # 触发await,等待任务完成
        all_results = [r.result() for r in finished]
        # 获取所有结果
        print("ALL RESULT:"+str(all_results))

URL = ['https://pythondict.com/wp-content/uploads/2019/07/2019073115192114.jpg',
       'https://pythondict.com/wp-content/uploads/2019/08/2019080216113098.jpg']
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop, URL))
loop.close()

注意: img = await session.get(url)
这时候,在你请求第一个图片获得数据的时候,它会切换请求第二个图片或其他图片,等第一个图片获得所有数据后再切换回来。从而实现多线程批量下载的功能,速度超快,下载超清大图用这个方法可以一秒一张。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦,有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

你不得不知道的python超级文献批量搜索下载工具

文献搜索对于广大学子来说真的是个麻烦事,如果你的学校购买的论文下载权限不够多,或者不在校园内,那就很头痛了。幸好,我们有Python制作的这个论文搜索工具,简化了我们学习的复杂性。

2020-05-28 补充:已用最新的scihub提取网,目前项目可用,感谢@lisenjor的分享。另外分享一个可用下载地址:https://sci-hub.shop/

2020-06-25 补充:增加关键词搜索批量下载论文功能。

​2021-01-07 补充:增加异步下载方式,加快下载速度;加强下载稳定性,不再出现文件损坏的情况。

2021-04-08 补充:由于sciencedirect增加了机器人检验,现在搜索下载功能需要先在HEADERS中填入Cookie才可爬取。

2021-04-25 补充:搜索下载增加百度学术、publons渠道。

2021-08-10 补充:修复scihub页面结构变化导致无法下载的问题,增加DOI下载函数。

1.什么是Scihub?

首先给大家介绍一下sci-hub这个线上数据,这个数据提供了 81,600,000 篇科学学术论文和文章下载。起初由一名叫 亚历珊卓·艾尔巴金 的研究生建立,她过去在哈佛大学从事研究时发现支付所需要的数百篇论文的费用实在是太高了,因此就萌生了创建这个网站,让更多人获得知识的想法

后来,这个网站越来越出名,逐渐地在更多地国家如印度、印度尼西亚、中国、俄罗斯等国家盛行,并成功地和一些组织合作,共同维护和运营这个网站。到了2017年的时候,网站上已有81600000篇学术论文,占到了所有学术论文的69%,基本满足大部分论文的需求,而剩下的31%是研究者不想获取的论文。

2.为什么我们需要用Python工具下载

在起初,这个网站是所有人都能够访问的,但是随着其知名度的提升,越来越多的出版社盯上了他们,在2015年时被美国法院封禁后其在美国的服务器便无法被继续访问,因此从那个时候开始,他们就跟出版社们打起了游击战。

游击战的缺点就是导致scihub的地址需要经常更换,所以我们没办法准确地一直使用某一个地址访问这个数据。当然也有一些别的方法可让我们长时间访问这个网站,比如说修改DNS,修改hosts文件,不过这些方法不仅麻烦,而且也不是长久之计,还是存在失效的可能的。

3.新姿势:用Python写好的API工具超方便下载论文

这是一个来自github的开源非官方API工具,下载地址为:

https://github.com/zaytoun/scihub.py

但由于作者长久不更新,原始的下载工具已经无法使用,Python实用宝典修改了作者的源代码,适配了中文环境的下载器,并添加了异步批量下载等方法:

https://github.com/Ckend/scihub-cn

欢迎给我一个Star,鼓励我继续维护这个仓库。如果你访问不了GitHub,请在 Python实用宝典 公众号后台回复 scihub,下载最新可用代码。

解压后使用CMD/Terminal进入这个文件夹,输入以下命令(默认你已经安装好了Python)安装依赖:

pip install -r requirements.txt

然后我们就可以准备开始使用啦!

这个工具使用起来非常简单,你可以先在 Google 学术(搜索到论文的网址即可)或ieee上找到你需要的论文,复制论文网址如:

http://img3.imgtn.bdimg.com/it/u=664814095,2334584570&fm=11&gp=0.jpg

然后在scihub-cn文件夹里新建一个文件叫download.py, 输入以下代码:

from scihub import SciHub

sh = SciHub()

# 第一个参数输入论文的网站地址
# path: 文件保存路径
result = sh.download('https://ieeexplore.ieee.org/document/26502', path='paper.pdf')

进入该文件夹后在cmd/terminal中运行:

python download.py

你就会发现文件成功下载到你的当前目录啦,名字为paper.pdf,如果不行,多试几次就可以啦,还是不行的话,可以在下方留言区询问哦。

上述是第一种下载方式,第二种方式你可以通过在知网或者百度学术上搜索论文拿到DOI号进行下载,比如:

from scihub import SciHub
sh = SciHub()
result = sh.download('10.1016/j.compeleceng.2020.106640', path='paper2.pdf')

下载完成后就会在文件夹中出现该文献:

除了这种最简单的方式,我们还提供了 论文关键词搜索批量下载 及 论文关键词批量异步下载 两种高级的下载方法。

我们在下文将会详细地讲解这两种方法的使用,大家可以看项目内的  test.py 文件,你可以了解到​论文搜索批量下载的方法。

进一步的高级方法在download.py 中可以找到,它可以实现论文搜索批量异步下载​,大大加快下载速度。具体实现​请看后文。

4.论文关键词批量下载

支持使用搜索的形式批量下载论文,比如说搜索关键词 量化投资(quant):

from scihub import SciHub

sh = SciHub()

# 搜索词
keywords = "quant"

# 搜索该关键词相关的论文,limit为篇数
result = sh.search(keywords, limit=10)

print(result)

for index, paper in enumerate(result.get("papers", [])):
    # 批量下载这些论文
    sh.download(paper["doi"], path=f"files/{keywords.replace(' ', '_')}_{index}.pdf")

运行结果,下载成功:

2021-04-25 更新:

由于读者们觉得Sciencedirect的搜索实在太难用了,加上Sciencedirect现在必须要使用Cookie才能正常下载,因此我新增了百度学术和publons这2个检索渠道。

由于 Web of Science 有权限限制,很遗憾我们无法直接使用它来检索,不过百度学术作为一个替代方案也是非常不错的。

现在默认的 search 函数调用了百度学术的接口进行搜索,大家不需要配置任何东西,只需要拉一下最新的代码,使用上述例子中的代码就可以正常搜索下载论文。

其他两个渠道的使用方式如下:

sciencedirect渠道:

由于 sciencedirect 加强了他们的爬虫防护能力,增加了机器人校验机制,所以现在必须在HEADER中填入Cookie才能进行爬取。

操作如下:

1.获取Cookie

2.使用sciencedirect搜索时,需要用search_by_science_direct函数,并将cookie作为参数之一传入:

from scihub import SciHub

sh = SciHub()

# 搜索词
keywords = "quant"

# 搜索该关键词相关的论文,limit为篇数
result = sh.search_by_science_direct(keywords, cookie="你的cookie", limit=10)

print(result)

for index, paper in enumerate(result.get("papers", [])):
    # 批量下载这些论文
    sh.download(paper["doi"], path=f"files/{keywords.replace(' ', '_')}_{index}.pdf")

这样就能顺利通过sciencedirect搜索论文并下载了。

publons渠道:

其实有了百度学术的默认渠道,大部分文献我们都能覆盖到了。但是考虑到publons​的特殊性,这里还是给大家一个通过publons渠道搜索下载的选项。

使用publons渠道搜索下载其实很简单,你只需要更改搜索的函数名即可,不需要配置Cookie:

from scihub import SciHub

sh = SciHub()

# 搜索词
keywords = "quant"

# 搜索该关键词相关的论文,limit为篇数
result = sh.search_by_publons(keywords, limit=10)

print(result)

for index, paper in enumerate(result.get("papers", [])):
    # 批量下载这些论文
    sh.download(paper["doi"], path=f"files/{keywords.replace(' ', '_')}_{index}.pdf")

5.异步批量下载优化,增加超时控制

这份代码已经运行了几个月,经常有同学反馈搜索论文后批量下载论文的速度过慢、下载的文件损坏的问题,这几天刚好有时间一起解决了。

下载速度过慢是因为之前的版本使用了串行的方式去获取数据和保存文件,事实上对于这种IO密集型的操作,最高效的方式是用 asyncio 异步的形式去进行文件的下载。

而下载的文件损坏则是因为下载时间过长,触发了超时限制,导致文件传输过程直接被腰斩了。

因此,我们将在原有代码的基础上添加两个方法:1.异步请求下载链接,2.异步保存文件。

此外增加一个错误提示:如果下载超时了,提示用户下载超时并不保存损坏的文件,用户可自行选择调高超时限制。

首先,新增异步获取scihub直链的方法,改为异步获取相关论文的scihub直链:

    async def async_get_direct_url(self, identifier):
        """
        异步获取scihub直链
        """
        async with aiohttp.ClientSession() as sess:
            async with sess.get(self.base_url + identifier) as res:
                logger.info(f"获取 {self.base_url + identifier} 中...")
                # await 等待任务完成
                html = await res.text(encoding='utf-8')
                s = self._get_soup(html)
                frame = s.find('iframe') or s.find('embed')
                if frame:
                    return frame.get('src') if not frame.get('src').startswith('//') \
                        else 'http:' + frame.get('src')
                else:
                    logger.error("Error: 可能是 Scihub 上没有收录该文章, 请直接访问上述页面看是否正常。")
                    return html

这样,在搜索论文后,调用该接口就能获取所有需要下载的scihub直链,速度很快:

def search(keywords: str, limit: int):
    """
    搜索相关论文并下载

    Args:
        keywords (str): 关键词
        limit (int): 篇数
    """

    sh = SciHub()
    result = sh.search(keywords, limit=limit)
    print(result)

    loop = asyncio.get_event_loop()
    # 获取所有需要下载的scihub直链
    tasks = [sh.async_get_direct_url(paper["doi"]) for paper in result.get("papers", [])]
    all_direct_urls = loop.run_until_complete(asyncio.gather(*tasks))
    print(all_direct_urls)

获取直链后,需要下载论文,同样也是IO密集型操作,增加2个异步函数:

async def job(self, session, url, destination='', path=None):
    """
    异步下载文件
    """
    if not url:
        return
    file_name = url.split("/")[-1].split("#")[0]
    logger.info(f"正在读取并写入 {file_name} 中...")
    # 异步读取内容
    try:
        url_handler = await session.get(url)
        content = await url_handler.read()
    except Exception as e:
        logger.error(f"获取源文件出错: {e},大概率是下载超时,请检查")
        return str(url)
    with open(os.path.join(destination, path + file_name), 'wb') as f:
        # 写入至文件
        f.write(content)
    return str(url)

async def async_download(self, loop, urls, destination='', path=None):
    """
    触发异步下载任务
    如果你要增加超时时间,请修改 total=300
    """
    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=300)) as session:
        # 建立会话session
        tasks = [loop.create_task(self.job(session, url, destination, path)) for url in urls]
        # 建立所有任务
        finished, unfinished = await asyncio.wait(tasks)
        # 触发await,等待任务完成
        [r.result() for r in finished]

这样,最后,在search函数中补充下载操作:

import asyncio
from scihub import SciHub


def search(keywords: str, limit: int):
    """
    搜索相关论文并下载

    Args:
        keywords (str): 关键词
        limit (int): 篇数
    """

    sh = SciHub()
    result = sh.search(keywords, limit=limit)
    print(result)

    loop = asyncio.get_event_loop()
    # 获取所有需要下载的scihub直链
    tasks = [sh.async_get_direct_url(paper["doi"]) for paper in result.get("papers", [])]
    all_direct_urls = loop.run_until_complete(asyncio.gather(*tasks))
    print(all_direct_urls)

    # 下载所有论文
    loop.run_until_complete(sh.async_download(loop, all_direct_urls, path=f"files/"))
    loop.close()


if __name__ == '__main__':
    search("quant", 10)

一个完整的下载过程就OK了:

比以前的方式舒服太多太多了… 如果你要增加超时时间,请修改async_download函数中的 total=300,把这个请求总时间调高即可。

最新代码前往GitHub上下载:

https://github.com/Ckend/scihub-cn

或者从Python实用宝典公众号后台回复 scihub 下载。

6.根据DOI号下载文献

最近有同学希望直接通过DOI号下载文献,因此补充了这部分内容。

import asyncio
from scihub import SciHub


def fetch_by_doi(dois: list, path: str):
    """
    根据 doi 获取文档
    Args:
        dois: 文献DOI号列表
        path: 存储文件夹
    """

    sh = SciHub()
    loop = asyncio.get_event_loop()
    # 获取所有需要下载的scihub直链
    tasks = [sh.async_get_direct_url(doi) for doi in dois]
    all_direct_urls = loop.run_until_complete(asyncio.gather(*tasks))
    print(all_direct_urls)

    # 下载所有论文
    loop.run_until_complete(sh.async_download(loop, all_direct_urls, path=path))
    loop.close()

if __name__ == '__main__':
    fetch_by_doi(["10.1088/1751-8113/42/50/504005"], f"files/")

默认存储到files文件夹中,你也可以根据自己的需求对代码进行修改。

7.工作原理

这个API的源代码其实非常好读懂。

一、找到sci-hub目前可用的域名

首先它会在这个网址里找到sci-hub当前可用的域名,用于下载论文:

https://whereisscihub.now.sh/

可惜的是,作者常年不维护,该地址已经失效了,我们就是在这里修改了该域名,使得项目得以重新正常运作:

二、对用户输入的论文地址进行解析,找到相应论文

1. 如果用户输入的链接不是直接能下载的,则使用sci-hub进行下载

2. 如果scihub的网址无法使用则切换另一个网址使用,除非所有网址都无法使用。

3.如果用户输入的是关键词,将调用sciencedirect的接口,拿到论文地址,再使用scihub进行论文的下载。

三、下载

1. 拿到论文后,它保存到data变量中

2. 然后将data变量存储为文件即可

此外,代码用到了一个retry装饰器,这个装饰器可以用来进行错误重试,作者设定了重试次数为10次,每次重试最大等待时间不超过1秒。

我们的文章到此就结束啦,如果你希望我们今天的文章,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦,有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典