社区所有版块导航
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

python: 自动下载sci-hub文献

生信技能树 • 4 年前 • 845 次点击  

科研神器sci-hub下载文献简单易用,但是仍然需要手动下载,如果待下载文献太多,就不那么友好了,最好可以自动批量下载,而这个正好是python requests库所擅长的。

本文目的仅用于学术交流及探讨requests库的用法。

需求及可行性分析

以sci-hub站点https://sci-hub.se/为例,测试文献名为Concise Review: MSC-Derived Exosomes for Cell-Free Therapy.,浏览器使用Chrome。

当我们输入文献名到sci-hub搜索框点击查询之后,可以发现页面自动跳转到了文献详情页,详情页的页面左侧是下载按钮和文献注释、连接等信息,右侧是自动载入的pdf版本的文献。

按F12打开网页调试工具查看此时的网页结构,点击左上的选择工具后再去页面中点击“下载”按钮,此时就会自动跳转到“下载”按键对应的网页布局的位置,如下图可以发现这个按钮是一个button组件,它的属性中有pdf的真实地址:https://twin.sci-hub.se/6288/3e57817d8f436407d5477c3b0affc56d/phinney2017.pdf,手动打开这个链接就是文献的pdf文件的源地址。

所以获得这个详情页面后,通过解析这个页面中的按钮的onlick属性就可以获得pdf文件地址。

现在需要知道如何去使用requests构造http请求来获取这个详情页面,在打开网页调试工具并且切换到“Network”选项卡的情况下,重新打开sci-hub站点https://sci-hub.se/,并搜索文献Concise Review: MSC-Derived Exosomes for Cell-Free Therapy.,结果如下图,我们点击第一个请求可以知道它是一个post请求,并且其状态是302页面重定向,很明显这个请求就是需要构造的请求。

第二个请求(stem.2575)就是详情页面的源码。

这个请求的地址和data等信息在下面图示中。

所以最终文献下载的思路就是,通过对https://sci-hub.se/构造一个post请求,页面自动重定向到文献详情页,然后通过解析详情页中pdf的源地址来下载。这些两个需求均可以使用requests库来完成。

具体代码测试

post请求除了接口地址之外,还需要提供附属的data信息,这个信息就是上图的Payload,可以看到data中上传了两个参数:sci-hub-plugin-check和request,sci-hub-plugin-check没有具体值,而request很重要,是要查询的文献名。




    
import requests
import re

url = 'https://sci-hub.se/'

data = {
    'sci-hub-plugin-check': '',
    'request': 'Concise Review: MSC-Derived Exosomes for Cell-Free Therapy.'
}

headers = {
    'referer': 'https://sci-hub.se/',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
}

# 请求
res = requests.post(
    url = url, 
    headers  =headers,
    data = data
)

res是返回的结果,res.content是返回的数据,如果是文本数据,使用res.text可以自动解码获取文本信息。另可以在res.history中找到跳转的网页,这也可以表明跳转成功了,代表res就是详情页面信息。

res.history
#[]
print(res.text)
#html>
#
#    
#        Sci-Hub | Concise Review: MSC-Derived Exosomes for Cell-Free Therapy. STEM CELLS, 35(4), 851–858 | 10.1002/stem.2575
#        
#        
#        
#    
#    
#    
#......

其实res.content和res.text是同样的内容,只不过一个已经是字符格式,一个是原始的二进制数据,比如将res.content进行解码后和res.text是一致的。

res.content.decode("utf-8") == res.text
#True

现在就需要从res.text中解析出pdf文件的下载地址,已经知道它在一个button组件的onclick属性中,这个信息可以使用正则给找到:在location.href='之后的字符串一直到pdf为止:

html

pat = re.compile("location.href='(.*?pdf)")
pat.findall(res.text)
#['https://twin.sci-hub.se/6288/3e57817d8f436407d5477c3b0affc56d/phinney2017.pdf']

于是就拿到了文献的源地址,现在只需要将这个文献地址构造一个get请求,然后返回的content就是文献数据了。

# 获取文献数据
pdf_path = pat.findall(res.text)[0]

pdf_res = requests.get(
    url = pdf_path
)

# paf_res.content写入文件
# 由于文献名中有:等特殊字符,导致无法在window中创建文件,先将名字中的这些奇怪的字符都给删除了
pdf_name = f"{re.sub('[:@#$&%.+]*', '', data['request'])}.pdf"
with open(pdf_name, "wb") as f:
    f.write(pdf_res.content)

然后当前文件夹下就可以看到pdf文件已经被正常下载下来了:

完整代码实现

将上述思路规整一下,既可以用于批量下载文献。

sci-hub并不需要设置headers,这里提供了headers作为一个选项以提高灵活性。

papers用于指定下载的文献,其中第四篇文献设置为“Error paper name”,以作为一个错误测试,出错的文献名将会保存在log.txt文件中。

import requests
import  re

# Necessary variable settings
url = 'https://sci-hub.se/'

papers = [
        "Concise Review: MSC-Derived Exosomes for Cell-Free Therapy.",
        "MSC exosome works through a protein-based mechanism of action",
        "Mammalian MSC from selected species: Features and applications",
        "Error paper name"
    ]

headers = {
    'referer': 'https://sci-hub.se/',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
}


# function definition
def get_html(url, papers = None, headers = None):
    if not url:
        raise Exception("url is None, please check...")

    if isinstance(papers, list):
        data = [{'sci-hub-plugin-check': '', 'request':p} for  p in papers]
        res = [requests.post(url, data = d, headers = headers) for d in data]
        res_text = [r.text for r in res]
        return res_text
    else:
        data = {'sci-hub-plugin-check': '', 'request':papers}
        res = requests.post(url, data = data, headers=headers)
        return res.text

def get_pdf_path(html, pattern = "location.href='(.*?pdf)"):
    pat = re.compile(pattern)

    if isinstance(html, list):
        pdf_path = [pat.findall(h) for h in html]
    else:
        pdf_path = pat.findall(html)

    return pdf_path

def get_pdf(path):
    res = []
    if  isinstance(path, list):

        for p in path:
            try:
                pdf = requests.get(p).content
            except Exception:
                pdf = None
            res.append(pdf)
    else:
        res.append(requests.get(path).content)
    return res


def main(url, papers = None, headers = None, pattern = "location.href='(.*?pdf)"):
    print(f"===== Get html =====")
    html = get_html(url, papers, headers)

    print(f"===== Get pdf path =====")
    pdf = get_pdf_path(html, pattern = pattern)
    pdf_path = [p[0] if len(p) > 0 else None for p in pdf]

    print(f"===== Get pdf content =====")
    pdf_content = get_pdf(pdf_path)

    if  not isinstance(papers, list):
        papers = [papers]

    with open("log.txt", "w") as f_log:
        for idx,p in enumerate(pdf_content):
            print(f"{idx+1}: {papers[idx]} \n   downloading...")
            if p == None:
                print(f"   failed and log into log_file...")
                f_log.write(f"{papers[idx]}\n")
            else:
                print(f"   success")
                pdf_name = re.sub('[\/:?*"<>|]*', '', papers[idx])
                pdf_name = f"{pdf_name}.pdf"

                with open(pdf_name, "wb") as f_pdf:
                    f_pdf.write(p)

# compatible with package
if __name__ == "__main__":
    main(url, papers = papers, headers = headers)

运行结果如下:

===== Get html =====
===== Get pdf path =====
===== Get pdf content =====
1: Concise Review: MSC-Derived Exosomes for Cell-Free Therapy.
   downloading...
   success
2: MSC exosome works through a protein-based mechanism of action
   downloading...
   success
3: Mammalian MSC from selected species: Features and applications
   downloading...
   success
4: Error paper name
   downloading...
   failed and log into log_file...

文件保存在当前文件夹:

20

22

文末友情推荐

《数据挖掘(GEO,TCGA,单细胞)2021第1 1期(年度收官)》

《生信入门课-2021第11期(年度收官)》



Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/125847