我是靠谱客的博主 勤劳百褶裙,最近开发中收集的这篇文章主要介绍Python项目1:核酸/蛋白序列本地管理工具v1.0工具简介版本与使用库说明所需文件说明具体使用方法介绍完整代码优化方向展望,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

进入正文之前先说点别的~

  1. 为什么会有这个项目?

有这个项目是因为上学期刚结束Python课程,期末要求交一个Python大作业,用课上学过的知识编写一个完整的Python程序。我思索再三,网上冲浪,也不知道写什么好,突然有一天就有了这么一个灵感。

  1. 为什么写这个内容?

虽然我相信万能的互联网一定有一个类似的工具,但是我觉得自己写一个属于自己的东西还是蛮有成就感的,而且这个工具对于我自己来说还是有用的。

  1. 后续还会有更新吗?

我的计划是:一定会有的,毕竟这只是一个为了交作业而交作业的Python项目,自然有很多需要完善的地方,这个我后续也会谈到。


~进入正文~


工具简介

这是一个本地的管理自己常用的核酸或蛋白的序列存储库,可以手动添加,也可以使用NCBI抓取工具对

目标序列进行获取,减少反复浏览NCBI数据库的次数;保存自己常用的序列数据也能够方便后续的分

析。

版本与使用库说明

工具使用的软件版本为:

  • Python 3.9.13

使用的相关库为:

  • tkinter

  • urllib

  • re

  • sleep

上述库都是Python标准库,只要安装了Python便无需单独下载!

所需文件说明

装饰图片:

  • icon.ico:工具对话框左上角呈现的图标

  • 可以自己随便找一个ico格式的图标,记得保存为icon.ico

  • 背景.gif:工具主页的图片。

  • 可以自己随便找一个,分辨率为678x387,记得保存为背景.gif

必要TXT文件:

  • table.txt:存储序列库的信息,用于存储和展示,包括序列类型、注册号、名称、长度、来源(初始可为空文件

  • seq.txt:存储序列的详细信息,用于存储和下载,包括序列类型、注册号、FASTA序列内容(初始可为空文件

主程序:

  • main.py:工具主程序。

  • 这个就是主要的程序了,可以直接把下面完整的代码粘到一个py文件里,就可以运行了。

为保证运行正确,上述文件应当在同一文件夹下!

具体使用方法介绍

主页介绍

双击main.py,进入主页:(这个根据你自己保存的程序文件为准,我交作业的时候写的是main.py)

双击后会弹出主页(上图)及黑色的Python运行框。

一共有三个选项,其中“本地序列库查询”和“从NCBI下载序列”两个按钮会在下面两节详细介绍;

“退出”按钮可以结束该程序。

本地序列库的使用方法

按1中的方法进入主页后,点击“本地序列库查询”,进入序列信息数据库:

可以看到此时数据库里面没有东西。

在页面顶部工具栏有四种操作方法,依次介绍:

添加新序列

我们点击“添加新序列”,会弹出以下窗口:

这是手动添加一条序列信息,需要我们手动输入,比如:

上图中填入的内容为:
    类型:Nucleotide
    注册号:AY230262
    名称:Homo sapiens NANOG mRNA, partial cds.
    长度:918
    来源:Homo sapiens (human)
    序列:
    ATGAGTGTGGATCCAGCTTGTCCCCAAAGCTTGCCTTGCTTTGAAGCATCCGACTGTAAA
    GAATCTTCAC
    CTATGCCTGTGATTTGTGGGCCTGAAGAAAACTATCCATCCTTGCAAATGTCTTCTGCTGA
    GATGCCTCA
    CACGGAGACTGTCTCTCCTCTTCCTTCCTCCATGGATCTGCTTATTCAGGACAGCCCTGAT
    TCTTCCACC
    AGTCCCAAAGGCAAACAACCCACTTCTGCAGAGAAGAGTGTCGCAAAAAAGGAAGACAA
    GGTCCCGGTCA
    AGAAACAGAAGACCAGAACTGTGTTCTCTTCCACCCAGCTGTGTGTACTCAATGATAGAT
    TTCAGAGACA
    GAAATACCTCAGCCTCCAGCAGATGCAAGAACTCTCCAACATCCTGAACCTCAGCTACAA
    ACAGGTGAAG
    ACCTGGTTCCAGAACCAGAGAATGAAATCTAAGAGGTGGCAGAAAAACAACTGGCCGAA
    GAATAGCAATG
    GTGTGACGCAGAAGGCCTCAGCACCTACCTACCCCAGCCTTTACTCTTCCTACCACCAGG
    GATGCCTGGT
    GAACCCGACTGGGAACCTTCCAATGTGGAGCAACCAGACCTGGAACAATTCAACCTGGA
    GCAACCAGACC
    CAGAACATCCAGTCCTGGAGCAACCACTCCTGGAACACTCAGACCTGGTGCACCCAATCC
    TGGAACAATC
    AGGCCTGGAACAGTCCCTTCTATAACTGTGGAGAGGAATCTCTGCAGTCCTGCATGCAGT
    TCCAGCCAAA
    TTCTCCTGCCAGTGACTTGGAGGCTGCCTTGGAAGCTGCTGGGGAAGGCCTTAATGTAA
    TACAGCAGACC
    ACTAGGTATTTTAGTACTCCACAAACCATGGATTTATTCCTAAACTACTCCATGAACATGCA
    ACCTGAAG
    ACGTGTGA

注意:

  • 类型只能是Nucleotide或Protein,因为该工具目的只存储这两个库的序列信息

  • 注册号对应NCBI上的ACCESSION

  • 名称对应NCBI上的DEFINITION

  • 来源对应NCBI上的SOURCE

  • 序列对应NCBI上的FASTA序列信息,不要标题,只输入序列

收到添加成功的信息后,我们可以看到界面更新了我们新加入的这一条序列的信息:

这就说明添加成功了!

当然,你也可以直接打开table.txt和seq.txt查看相关内容!

删除序列

作为示例,我们这样添加信息到库中:

(仅作示例!)

如果要删除序列,可点击“删除序列”,进入删除序列界面:

这里可以接受通过注册号删除,而且可以同时删除多条!

注意,在同时删除多条时,一定要用英文逗号间隔!

示例:

点击“删除”:

删除成功,没有相关信息了!

下载目标序列

如果想要下载自己库中的序列,可以使用“下载目标序列”菜单。点击后进入:

可以同时下载多条序列,但是需要以英文逗号分隔!

如图示例,我下载序列AA2222和AA5555到C:/Users/cien/Desktop/download.txt文件中:(需要修改为自己的路径!

点击“下载”,就可以在对应的文件中看到下载的信息了:

清空数据库

点击“清空数据库”,可以清除页面显示和本地两个文件table.txt和seq.txt:

NCBI序列爬取工具使用方法

点击主页的第二个按钮“从NCBI下载序列”可以进入NCBI序列下载工具:

可以看到,需要我们提交一些信息,从而帮助我们自动去NCBI抓取我们想要的序列信息!

填写说明:

  • 请求库只能是核酸核心库nuccore和蛋白库protein,拼写一定要方框中书写所示!

  • 序列号可以一个或多个,但是必须以英文逗号间隔!

  • 可以一次请求多个,但是必须隶属于同一个库!

  • “是否将结果存储到库”:是否把爬取到的内容放在刚刚我们设计的本地库中

  • “是否将结果存储到本地文件”:是否要把爬取的FASTA文件整合为一个文件存储到本地计算机

  • 如果选择了这一项,一定要给出文件路径!!!

下面是一个填写示例:

填写内容:
    请求库:nuccore
    序列号:AY230262,JF912492
    是
    是
    路径:C:/Users/cien/Desktop/download.txt(需要修改成自己的路径!)

点击“抓取”,提交。

在爬取过程中,Python对话框还会有提示信息输出:

抓取结束后,我们还可以在自己的库中看到抓取下来的信息:

同时,我们在download.txt文件中也找到了整合好的文件:

这样的文件就方便我们后续分析了!

完整代码

from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
from urllib.request import urlopen
import re
from time import sleep

def main_page():
    """
    主界面配置
    """
    window = Tk()
    # 外框配置
    window.title("主页")
    window.geometry("800x600")
    window.iconbitmap("icon.ico")
    # 图片
    main_img = PhotoImage(file="背景.gif")
    img_lab = Label(window, image=main_img).pack(side="top")
    # 标题文字
    main_text = Label(window,
        text="核酸/蛋白序列本地管理工具",
        font=("微软雅黑", 20, "bold"),
        borderwidth=10)
    main_text.pack(fill=X)
    # 按钮控件
    b1 = Button(window,
        text="本地序列库查询",
        font=("宋体", 15, "bold"),
        bg="#DDEBE9",
        command=seq_db)
    b2 = Button(window,
        text="从NCBI下载序列",
        font=("宋体", 15, "bold"),
        bg="#3C8883",
        command=crawl_page)
    b3 = Button(window,
        text="退出",
        font=("宋体", 15, "bold"),
        bg="#415F90",
        command=window.quit)
    b1.pack()
    b2.pack()
    b3.pack()
    # 提交运行
    window.mainloop()

def seq_db():
    """
    序列库界面
    """
    # 初始化窗口
    tb = Tk()
    tb.title("数据库")
    tb.geometry("800x600")
    tb.iconbitmap("icon.ico")
    # 表格设置
    table_frame = Frame(tb)
    table_frame.pack()
    columns = ['类型', '注册号', '名称', '长度', '来源']
    table = ttk.Treeview(
        master=tb,
        height=30,
        columns=columns,
        show="headings"
    )
    table.heading(column='类型', text='类型')
    table.heading(column='注册号', text='注册号')
    table.heading(column='名称', text='名称')
    table.heading(column='长度', text='长度')
    table.heading(column='来源', text='来源')
    table.column('类型', width=150, anchor=S)
    table.column('注册号', width=150, anchor=S)
    table.column('名称', width=150, anchor=S)
    table.column('长度', width=150, anchor=S)
    table.column('来源', width=150, anchor=S)
    # 初始载入本地文件
    load_file(table)
    # 顶部工具栏
    main_menu = Menu(tb)
    main_menu.add_command(label="添加新序列", command=lambda:insert(table))
    main_menu.add_command(label="删除序列", command=lambda:delete(table))
    main_menu.add_command(label="下载目标序列", command=download)
    main_menu.add_command(label="清空数据库", command=lambda:del_all(table))
    tb.config (menu=main_menu)
    # 布局
    table.pack(fill=BOTH, expand=True)

def load_file(table):
    """
    从本地文件中读取序列并插入表格
    """
    file = open("table.txt", "rt")
    data = file.readlines()
    if data != []:
        for i in data:
            sub = i.strip().split("t")
            table.insert('', END,
                values=(sub[0], sub[1], sub[2], sub[3], sub[4]))
    file.close()

def insert(table):
    """
    插入一条新记录
    """
    # 创建窗体
    ins = Tk()
    ins.title("插入一条新记录")
    ins.geometry("250x200")
    ins.iconbitmap("icon.ico")
    # 创建标签对象
    label1 = Label(ins, text="类型: ").grid(row=0)
    label2 = Label(ins, text="注册号: ").grid(row=1)
    label3 = Label(ins, text="名称: ").grid(row=2)
    label4 = Label(ins, text="长度: ").grid(row=3)
    label5 = Label(ins, text="来源: ").grid(row=4)
    label6 = Label(ins, text="序列: ").grid(row=5)
    # 创建输入控件对象
    entry1 = Entry(ins)
    entry2 = Entry(ins)
    entry3 = Entry(ins)
    entry4 = Entry(ins)
    entry5 = Entry(ins)
    entry6 = Entry(ins)
    entry1.grid(row=0, column=1)
    entry2.grid(row=1, column=1)
    entry3.grid(row=2, column=1)
    entry4.grid(row=3, column=1)
    entry5.grid(row=4, column=1)
    entry6.grid(row=5, column=1)
    # 按钮对象
    button = Button(ins, text="插入",
      font=("微软雅黑", 10, "bold"),
      command=lambda:update(entry1.get(), entry2.get(), entry3.get(),
          entry4.get(), entry5.get(), entry6.get(), table, ins))
    button.grid(row=6, column=1)
    
def update(e1, e2, e3, e4, e5, e6, table, win):
    """
    更新本地文件
    """
    # 写入表格文件
    file = open("table.txt", "a")
    file.write("%st%st%st%st%sn"%(e1, e2, e3, e4, e5))
    file.close()
    # 写入序列文件
    file = open("seq.txt", "a")
    seq = ''
    for i in e6:
        if i != "n":
            seq += i.strip()
    file.write("%st%st%sn"%(e1, e2, seq))
    file.close()
    # 删除显示的内容并重新加载
    for item in table.get_children():
        table.delete(item)
    load_file(table)
    # 弹出信息并摧毁窗口
    messagebox.showinfo(title="提示", message="添加成功!")
    win.destroy()

def delete(table):
    """
    删除指定的数据
    """
    # 创建窗体
    dele = Tk()
    dele.title("删除记录")
    dele.geometry("230x100")
    dele.iconbitmap("icon.ico")
    # 创建标签对象
    label = Label(dele, text="请输入要删除的序列注册号: ").grid(row=0)
    label2 = Label(dele, text="(如果有多条,请务必以英文','间隔!!!)").grid(row=2)
    # 创建输入控件对象
    entry = Entry(dele)
    entry.grid(row=1, column=0)
    # 按钮对象
    button = Button(dele, text="删除",
      font=("微软雅黑", 10, "bold"),
      command=lambda:update2(entry.get(), table, dele))
    button.grid(row=3, column=0)

def update2(e, table, win):
    """
    因删除重写文件
    """
    # 重写表格文件
    del_line = e.split(",")
    count = 0
    with open("table.txt", "rt") as f:
        lines = f.readlines()
    with open("table.txt","wt") as f_w:
        for line in lines:
            mark = 0
            for i in del_line:
                if i in line.split("t"):
                    count += 1
                    mark = 1
                    continue
            if mark == 0:
                f_w.write(line)
    # 重写序列文件
    with open("seq.txt", "rt") as f:
        lines = f.readlines()
    with open("seq.txt","wt") as f_w:
        for line in lines:
            mark = 0
            for i in del_line:
                if i in line.split("t"):
                    mark = 1
                    continue
            if mark == 0:
                f_w.write(line)
    # 删除并重新加载
    for item in table.get_children():
        table.delete(item)
    load_file(table)
    # 弹出信息并摧毁窗口
    if count == len(del_line):
        messagebox.showinfo(title="提示", message="全部删除成功!")
    elif count < len(del_line) and count > 0:
        messagebox.showinfo(title="提示", message="只删除了%s条!"%count)
    elif count == 0:
        messagebox.showinfo(title="提示", message="没有找到数据!")
    win.destroy()

def download():
    """
    下载本地数据库中指定的序列
    """
    # 创建窗体
    dl = Tk()
    dl.title("下载序列")
    dl.geometry("500x150")
    dl.iconbitmap("icon.ico")
    # 创建标签对象
    label = Label(dl, text="请输入要下载的序列注册号: ").grid(row=0, sticky=W)
    label2 = Label(dl, text="(如果有多条,请务必以英文','间隔!!!)").grid(row=2, column=1, sticky=W)
    label3 = Label(dl, text="下载路径: ").grid(row=3, sticky=W)
    # 路径变量
    path = StringVar()
    # 创建输入控件对象
    entry = Entry(dl)
    entry2 = Entry(dl, textvariable=path)
    entry.grid(row=1, column=1)
    entry2.grid(row=3, column=1)
    # 按钮对象
    button = Button(dl, text="选择路径",
      font=("微软雅黑", 10, "bold"),
      command=lambda:open_file_name(entry2))
    button.grid(row=3, column=2, sticky=W)
    button2 = Button(dl, text="下载",
      font=("微软雅黑", 10, "bold"),
      command=lambda:download_all(entry.get(), entry2.get(), dl))
    button2.grid(row=4, column=1)

def open_file_name(entry):
    """
    返回获取的文件路径
    """
    entry.insert(0, filedialog.askopenfilename())

def download_all(number, file_path, win):
    """
    按指定路径下载需要的序列    
    """
    acc_num = number.split(",")
    name_list = []
    seq_list = []
    # 从表格文件中获取名字
    lines = open("table.txt", "rt").readlines()
    for i in acc_num:
        for line in lines:
            if i in line.split("t"):
                name_list.append(line.split("t")[2])
                break
    # 从序列文件中获取序列
    lines = open("seq.txt", "rt").readlines()
    for i in acc_num:
        for line in lines:
            if i in line.split("t"):
                seq_list.append(line.split("t")[2])
                break
    # 写入目标文件
    file = open(file_path, 'wt')
    for i in range(len(name_list)):
        file.write("> %s %sn"%(acc_num[i], name_list[i]))
        file.write("%sn"%seq_list[i].strip())
    messagebox.showinfo(title="提示", message="下载成功!")
    win.destroy()

def del_all(table):
    """
    清空全部数据
    """
    for item in table.get_children():
        table.delete(item)
    with open("table.txt",'a+',encoding='utf-8') as f:
        f.truncate(0)
    with open("seq.txt",'a+',encoding='utf-8') as f:
        f.truncate(0)

def crawl_page():
    """
    从NCBI上爬取想要的序列页面
    """
    cr = Tk()
    cr.title("NCBI抓取")
    cr.geometry("400x300")
    cr.iconbitmap("icon.ico")
    # 请求库选择
    label1 = Label(cr, text="请求库: ").grid(row=0, sticky=W)
    entry1 = Entry(cr)
    entry1.insert(0, "填入 nuccore 或 protein")
    entry1.grid(row=0, column=1)
    # 序列号输入
    label2 = Label(cr, text="序列号(以','间隔): ").grid(row=1, sticky=W)
    entry2 = Entry(cr)
    entry2.grid(row=1, column=1)
    # 是否存储到本地库中
    label3 = Label(cr, text="是否将结果存储到库: ").grid(row=2, sticky=W)
    entry3 = Entry(cr)
    entry3.insert(0, "填入 是 或 否")
    entry3.grid(row=2, column=1)
    # 是否输出到某文件
    label4 = Label(cr, text="是否将结果存储到本地文件: ").grid(row=3, sticky=W)
    entry4 = Entry(cr)
    entry4.insert(0, "填入 是 或 否")
    entry4.grid(row=3, column=1)
    # 获取路径
    entry5 = Entry(cr)
    entry5.grid(row=4, column=1)
    button = Button(cr, text="选择路径",
      font=("微软雅黑", 10, "bold"),
      command=lambda:open_file_name(entry5))
    button.grid(row=4, column=0, sticky=W)
    # 提交运行
    button2 = Button(cr, text="抓取",
      font=("微软雅黑", 10, "bold"),
      command=lambda:crawl(entry1.get(), entry2.get(), entry3.get(), entry4.get(), entry5.get(), cr))
    button2.grid(row=5, column=1, sticky=W)

def crawl(repo, accession, store, download, path=None, win=None):
    """
    爬取NCBI相应内容
    """
    file1 = open("table.txt", "a")
    file2 = open("seq.txt", "a")
    if path != '':
        file3 = open(path, "a")
    for i in accession.split(","):
        print("正在爬取%s主页信息..."%i)
        ## 爬取主页
        # 一级请求,获得uid号
        url = "https://www.ncbi.nlm.nih.gov/" + repo + "/" + i
        f = urlopen(url)
        temp = f.read().decode("utf-8")
        f.close()
        find_uid = re.compile(r'ncbi_uid=(.*?)&')
        res = re.search(find_uid, temp).group()
        uid = res.split("=")[1].split("&")[0]
        # 同级请求fasta,获得phid号
        url = "https://www.ncbi.nlm.nih.gov/" + repo + "/" + i + "?report=fasta"
        f = urlopen(url)
        temp = f.read().decode("utf-8")
        f.close()
        find_phid = re.compile(r'ncbi_phid=(.*?)" /')
        res = re.search(find_phid, temp).group()
        phid = res.split("=")[1].split(""")[0]
        sleep(5)    # 礼貌访问
        # 二级请求
        url = "https://www.ncbi.nlm.nih.gov/sviewer/viewer.fcgi?id="+uid
        f = urlopen(url)
        result = f.read().decode("utf-8")
        f.close()
        # 根据请求库不同进行存储
        name = re.findall(r'DEFINITION(.*?)nACCESSION', result)[0].strip()
        source = re.findall(r'SOURCE(.*?)n  ORGANISM', result)[0].strip()
        if repo == "nuccore":
            seq_type = "Nucleotide"
            length = re.findall(r'%s(.*?) bp'%i, result)[0].strip()
        elif repo == "protein":
            seq_type = "Protein"
            length = re.findall(r'%s(.*?) aa'%i, result)[0].strip()
        # 根据需要进行本地库存储
        if store == "是":
            file1.write("%st%st%st%st%sn"%(seq_type, i, name, length, source))
        print("%s主页信息已爬取,准备爬取FASTA信息..."%i)
        sleep(5)    # 礼貌访问
        ## 爬取FASTA序列
        # 三级请求,获取FASTA页面
        url = "https://www.ncbi.nlm.nih.gov/sviewer/viewer.fcgi?id=%s&db=%s&report=fasta&extrafeat=null&conwithfeat=on&hide-cdd=on&retmode=html&ncbi_phid=%s&withmarkup=on&tool=portal&log$=seqview&maxdownloadsize=1000000"%(uid, repo, phid)
        f = urlopen(url)
        result = f.read().decode("utf-8")
        f.close()
        # 依情况存储
        if store == "是":
            # 获取一行序列
            seq = ''
            raw = result.split("n")[1:]
            for i in raw:
                seq += i
            # 存储
            file2.write("%st%st%sn"%(seq_type, i, seq))
        if download == "是":
            file3.write(result)
        print("已完成爬取%s!请等待下一轮爬取..."%i)
        sleep(5)    # 礼貌访问,等待下一轮请求
    file1.close()
    file2.close()
    if path != '':
        file3.close()
    messagebox.showinfo(title="提示", message="爬取完成!")
    win.destroy()

# 运行
main_page()

优化方向展望

对于这个小工具,我有如下优化的考虑:

  1. 使用数据库对存储进行优化;

  1. 设计更好的界面;

  1. 完善异常处理

  1. 新的功能设计

  1. ……

最后

以上就是勤劳百褶裙为你收集整理的Python项目1:核酸/蛋白序列本地管理工具v1.0工具简介版本与使用库说明所需文件说明具体使用方法介绍完整代码优化方向展望的全部内容,希望文章能够帮你解决Python项目1:核酸/蛋白序列本地管理工具v1.0工具简介版本与使用库说明所需文件说明具体使用方法介绍完整代码优化方向展望所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部