Magnetico 磁力信息收集器,Mysql数据库版

一个土耳其程序员正在忙于创建一个名为“magnetico”的匿名和自主托管的BitTorrent搜索引擎。它允许具有互联网连接的用户访问DHT空间中的大量洪流,而不需要依赖任何中央实体。随着进一步的改进,magnetico可能有助于BitTorrent生态系统的完全分散化。

什么是magnetico?

    magnetico利用BitTorrent的DTH来查找内容和重要的对等体。它旨在创建个人torrent搜索引擎,并保持其创建的索引完全私有。

magnetico是第一个为最终用户设计的自主BitTorrent DHT搜索引擎套件。套件由两个包组成:

magneticod:自动BitTorrent DHT抓取器和元数据抓取器。

magneticow:轻薄的web界面。

magneticod在后台运行,并且DTH网络从对等体获取数据,magneticow是用于搜索和查看种子的轻量级Web界面。

直接通过pip安装的magneticod是使用sqlite数据库的,不利于分布式收集、大型数据库使用,这里介绍如果使用mysql来存储收集到的数据。

代码

# magneticod - Autonomous BitTorrent DHT crawler and metadata fetcher.
# Copyright (C) 2017  Mert Bora ALPER <bora@boramalper.org>
# Dedicated to Cemile Binay, in whose hands I thrived.
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
import logging
import pymysql
import time
import typing
import os

from magneticod import bencode
from .constants import PENDING_INFO_HASHES


class Database:

    def __init__(self, database) -> None:
        self.__db_conn = self.__connect(database)

        # We buffer metadata to flush many entries at once, for performance reasons.
        # list of tuple (info_hash, name, total_size, discovered_on)
        self.__pending_metadata = []  # type: typing.List[typing.Tuple[bytes, str, int, int]]
        # list of tuple (info_hash, size, path)
        self.__pending_files = []  # type: typing.List[typing.Tuple[bytes, int, bytes]]

    @staticmethod
    def __connect(database) -> pymysql.Connection:
        db_conn = pymysql.connect("localhost", "root", "password", "dht", charset="utf8")

        # You need create tables by your self.

        # CREATE TABLE `files` (
        #   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
        #   `torrent_id` int(11) unsigned NOT NULL,
        #   `size` bigint(20) NOT NULL,
        #   `path` text NOT NULL,
        #   PRIMARY KEY (`id`)
        # ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

        # CREATE TABLE `torrents` (
        #   `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
        #   `info_hash` varchar(64) NOT NULL,
        #   `name` text NOT NULL,
        #   `total_size` bigint(20) NOT NULL DEFAULT '0',
        #   `discovered_on` int(11) NOT NULL DEFAULT '0',
        #   `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        #   `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        #   `actived_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        #   `visited_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        #   PRIMARY KEY (`id`),
        #   KEY `info_hash_index` (`info_hash`)
        # ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4

        # And you need update this code for connect your mysql server.
        return db_conn

    def add_metadata(self, info_hash: bytes, metadata: bytes) -> bool:
        files = []
        discovered_on = int(time.time())
        info_hash = info_hash.hex()
        try:
            info = bencode.loads(metadata)  # type: dict

            assert b"/" not in info[b"name"]
            name = info[b"name"].decode("utf-8")

            if b"files" in info:  # Multiple File torrent:
                for file in info[b"files"]:
                    assert type(file[b"length"]) is int
                    # Refuse trailing slash in any of the path items
                    assert not any(b"/" in item for item in file[b"path"])
                    path = "/".join(i.decode("utf-8") for i in file[b"path"])
                    files.append([info_hash, file[b"length"], path])
            else:  # Single File torrent:
                assert type(info[b"length"]) is int
                files.append([info_hash, info[b"length"], name])
        # TODO: Make sure this catches ALL, AND ONLY operational errors
        except (bencode.BencodeDecodingError, AssertionError, KeyError, AttributeError, UnicodeDecodeError, TypeError):
            return False

        self.__pending_metadata.append([info_hash, name, sum(f[1] for f in files), discovered_on])
        self.__pending_files += files

        logging.info("Added: `%s`", name)

        # Automatically check if the buffer is full, and commit to the SQLite database if so.
        if len(self.__pending_metadata) >= PENDING_INFO_HASHES:
            self.__commit_metadata()

        return True

    def is_infohash_new(self, info_hash):
        info_hash = info_hash.hex()
        if info_hash in [x[0] for x in self.__pending_metadata]:
            return False
        cur = self.__db_conn.cursor()
        try:
            cur.execute("SELECT count(info_hash) FROM torrents where info_hash = %s;", [info_hash])
            x, = cur.fetchone()
            ise = (x == 0)
            if not ise:
                cur.execute("UPDATE torrents SET actived_at = now() where info_hash = %s;", [info_hash])
                self.__db_conn.commit()
            return ise
        finally:
            cur.close()

    def __commit_metadata(self) -> None:
        cur = self.__db_conn.cursor()

        # Insert metadata
        for metadata in self.__pending_metadata:
            try:
                # Insert torrents
                cur.execute(
                    "INSERT INTO torrents (info_hash, name, total_size, discovered_on) VALUES (%s, %s, %s, %s);",
                    metadata
                )
                self.__db_conn.commit()
            except pymysql.err.IntegrityError as e:
                self.__db_conn.rollback()
                logging.exception("%s metadata is could NOT commit metadata to the database.", metadata[0])
            except:
                self.__db_conn.rollback()
                logging.exception("%s metadata is could NOT commit metadata to the database.", metadata[0])

        # And insert files
        try:
            cur.executemany(
                "INSERT INTO files (torrent_id, size, path) VALUES ((SELECT id FROM torrents WHERE info_hash=%s), %s, %s);",
                self.__pending_files
            )

            self.__db_conn.commit()
            logging.info("%d metadata (%d files) are committed to the database.", len(self.__pending_metadata), len(self.__pending_files))
            self.__pending_metadata.clear()
            self.__pending_files.clear()
        except:
            self.__db_conn.rollback()
            logging.exception("Could NOT commit metadata to the database! (%d metadata are pending)",
                              len(self.__pending_metadata))
        finally:
            cur.close()

    def close(self) -> None:
        if self.__pending_metadata:
            self.__commit_metadata()
        self.__db_conn.close()

在此之前,你需要通过pip方式安装Magnetico,并安装Mysql 服务器,之后通过pip安装PyMysql这个插件。修改数据库信息后替换Magnetico自带persistence.py文件,一般在/usr/local/lib/python3.5/dist-packages/magneticod目录。

建立两个表,在代码注释中有,建立好索引。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容