Updates from 七月, 2018 Toggle Comment Threads | 键盘快捷键

  • jinzihao pm3:04 on 2018年7月30日 链接地址 | 回复  

    利用Google快照,恢复误删的WordPress数据库 

    起因:前些天试图修复MySQL经常性崩溃的问题,结果误删WordPress数据库(误删ibdata文件后重启了MySQL进程,失去了恢复机会)。由于之前从未做过备份,本博客所有文章全部丢失。但Google默默地为我的网站作了快照,所以仍然有机会从Google快照中恢复网站内容。

    抓取快照网址

    1. 将Google搜索每页搜索结果数设为最大值100

    2. 使用Google搜索site:jinzihao.me

    3. 对于每页搜索结果(“for page in search_results:”),在浏览器控制台中执行以下代码:

    function saveData(data, filename) {
        var a = document.createElement('a');
        var url = window.URL.createObjectURL(data);
        a.href = url;
        a.download = filename;
        a.click();
        window.URL.revokeObjectURL(url);
    }
    
    var regex = /"(https:\/\/webcache.googleusercontent.com\/.*?)"/g;
    var urls = [];
    match = regex.exec(document.body.innerHTML);
    while (match != null) {
        urls.push(match[1] + '&vwsrc=1');
        match = regex.exec(document.body.innerHTML);
    }
    saveData(new Blob([urls.join("\n")]), 'url.txt');

    上述代码提取网页中所有快照链接(https://webcache.googleusercontent.com/……),将其保存到文件url.txt。添加”vwsrc=1″参数使Google快照显示网页原始的HTML代码,便于之后重建网站内容。

    由于搜索结果页数不多,本人采用了手动翻页的方式来抓取快照链接。之后将几个网址列表(url.txt)合并到一个文件,这就是下一步抓取的目标列表了。

    图1. 抓取到的快照网址列表

    抓取快照内容

    1. 打开一个Google快照页面,确保其在https://webcache.googleusercontent.com域名下,这样我们才能通过AJAX请求抓取其他快照页面。

    2. 将前一步抓取的快照网址列表放置在服务器上,并在服务器上设置好CORS策略,这样我们可以通过AJAX请求获取到该列表。

    3. 在浏览器控制台中执行以下代码:

    function saveData(data, filename) {
        var a = document.createElement('a');
        var url = window.URL.createObjectURL(data);
        a.href = url;
        a.download = filename;
        a.click();
        window.URL.revokeObjectURL(url);
    }
    
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", "https://lab.jinzihao.me/cors/urllist.txt", false);
    xmlhttp.send();
    urls = xmlhttp.responseText.split("\n");
    for (var url of urls) {
        console.log(url);
        xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", url, false);
        xmlhttp.send();
        url = url.split("+")[0].split(":")[4];
        console.log(url);
        saveData(new Blob([xmlhttp.responseText]), "jinzihao_me_" + btoa(url));
    }

    这样就将网站在Google快照中的所有页面抓取了下来,其中文件名是jinzihao_me_ + base64编码的原始网址,文件内容则是Google快照页面的全部HTML代码。

    图2. 抓取到的快照页面

    重建网站

    首先清空wp_posts表,确保文章ID不会产生冲突:

    truncate table wp_posts;

    接下来使用如下Python程序,遍历上一步抓取到的快照页面,并将其插回到MySQL数据库,重建wp_posts表(由于MySQLdb模块只支持Python 2,本代码只能运行在Python 2上):

    #!/usr/bin/env python
    #!-*- coding: UTF-8 -*-
    import os
    import sys
    import html
    import HTMLParser
    from bs4 import BeautifulSoup
    import time
    import MySQLdb
    
    os.environ['TZ'] = 'Asia/Chongqing'
    time.tzset()
    
    result = dict()
    
    db = MySQLdb.connect('localhost', '****username****', '****password****', '****dbname****', charset='utf8')
    cursor = db.cursor()
    
    for filename in os.listdir(sys.argv[1]):
        print("File: " + filename)
        # f = open(os.path.join(sys.argv[1], filename), 'r', encoding='utf-8')
        f = open(os.path.join(sys.argv[1], filename), 'r')
        content = f.read()
        f.close()
        soup = BeautifulSoup(content, 'html.parser')
        # inner_content = html.unescape(soup.find_all('pre')[0].decode_contents())
        inner_content = HTMLParser.HTMLParser().unescape(soup.find_all('pre')[0].decode_contents())
        inner_soup = BeautifulSoup(inner_content, 'html.parser')
        permalinks = []
        gmt_times = []
        local_times = []
        post_types = []
        metas = inner_soup.select('span.meta')
        for meta in metas:
            if len(meta.a['href'].split('#')) == 1:
                if meta.abbr is None:
                    post_types.append('page')
                    post_time = '1970-01-01 08:00:00'
                else:
                    post_types.append('post')
                    post_time = meta.abbr['title']
                gmt_times.append(post_time[:10] + ' ' + post_time[11:19])
                local_times.append(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(time.mktime(time.strptime(gmt_times[-1], '%Y-%m-%d %H:%M:%S')) + 57600)))
                permalinks.append(meta.a['href'])
    
    
        posts = inner_soup.select('div.postcontent')
    
        for id, post in enumerate(posts):
            post_id = int(post['id'].split('-')[1])
            if post.h2 is None:
                post_title = ''
                post_content = post.decode_contents()
            elif post.h2.a is None:
                post_title = post.h2.decode_contents()
                post_content = post.decode_contents()
                post_content = post_content[post_content.find('</h2>') + 5:]
            else:
                post_title = post.h2.a.decode_contents()
                post_content = post.decode_contents()
                post_content = post_content[post_content.find('</h2>') + 5:]
            if (post_id not in result) or (len(post_content) > len(result[post_id][1])):
                result[post_id] = [post_title, post_content, gmt_times[id], local_times[id], permalinks[id], permalinks[id].split('/')[-2], post_types[id]]
    
    for id, data in result.items():
        sql = "INSERT INTO wp_posts (ID, post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
        cursor.execute(sql, (id, 1, data[3], data[2], data[1], data[0], '', 'publish', 'open', 'open', '', data[5], '', '', data[3], data[2], '', 0, data[4], 0, data[6], '', 0))
    
    db.commit()
    db.close()

    这段代码使用Beautiful Soup对Google快照页面做了解析,提取最外层的<pre>元素,其中包含被快照的网页的HTML代码。对其进行一次HTML反转义,再次用Beautiful Soup进行解析,提取其中的<span class=”meta”>,获取到文章的元信息(时间和网址);提取其中的<div class=”postcontent”>,获取到文章ID和内容。最后将其插入到wp_posts表,即可重建WordPress文章数据。

     
    • 高飞 上午12:46 on 2018年8月15日 链接地址 | 回复

      非常棒的技术,有编程方面的问题向你请教,看到麻烦回复/联系,谢谢!997868589@qq.com

      • jinzihao 上午11:29 on 2018年8月15日 链接地址 | 回复

        您好,我的邮箱是903703287@qq.com,欢迎邮件联系

  • jinzihao pm9:11 on 2015年10月8日 链接地址 | 回复  

    在OJ上遇到结果错误(wrong answer),有时是选取的数据类型上限不够大,而上限不够大不一定会在输入数据的时候暴露出问题…有可能输入的数据在char范围内,但在程序中相乘/累加之后直接超出了long long的上限…这时可以根据需要采用取模(mod)或取符号(sgn)来控制数据范围…

     
  • jinzihao pm7:43 on 2015年9月23日 链接地址 | 回复  

    世界,您好!  

    欢迎使用WordPress。这是您的第一篇文章。编辑或删除它,然后开始写作吧!

     
c
写新的
j
下一篇文章/下一个回复
k
前一篇文章/以前的回复
r
回复
e
编辑
o
显示/隐藏 回复
t
回到顶部
l
go to login
h
show/hide help
shift + esc
取消