爬虫工具

爬虫之微信公众号

2019-02-27  本文已影响161人  7e3c6097c856
wechat_official_account.png

与自小一起玩的一小伙伴,昨晚聊天,说他导师需要这个公众号爆炸实验室的文章,有没有兴致。刚好有兴趣,就试一试。
总体思路是:

  • 获取文章链接及对应标题;
  • 将链接写入文本文档或存入数据库;
  • 单读解析每一个网址并下载至本地。

下文按照这三个步骤逐次展开。

获取文章链接

我采取的是以下两种方法:

将链接写入文本文档

解析网页

# coding:utf-8
"""
0. Win 10 教育版 + Python 3.7.0
1. 我的Chrome是 Version 72.0.3626.119 (Official Build) (32-bit);
2. 你需要安装selenium包:pip install selenium;
3. 你需要安装BeautifulSoup包: pip install beautifulsoup4;
4. 你需要将驱动文件 chromedriver.exe 放入环境变量,该文件在selenium官网找一下,不同系统用不一样的驱动
"""
from selenium import webdriver
from bs4 import BeautifulSoup
import win32api
import win32con
import random
import time
import os


def get_all_link(file='index.html'):
    """
    从index.html提取每篇文章链接及标题,然后保存至bomblab.txt
    :param file:
    :return:
    """

    with open(file, 'r+', encoding='utf-8') as file:
        soup = BeautifulSoup(file, 'lxml')
        for i in soup.find_all('a', target="_blank"):
            print(i.text.strip() + '\t' + i['href'], file=open('bomblab.txt', 'a+', encoding='utf-8'))
            # print(i['href'])
            # print(i.text.strip().strip('\n'))


def download_single_spage(url):
    """
    读取bomblab.txt中文章链接,然后下载并保存该文章至本地。默认为Chrome默认保存地址。
    :param url:
    :return:
    """

    # 打开另存为mhtml功能
    options = webdriver.ChromeOptions()
    options.add_argument('--save-page-as-mhtml')

    # 设置chromedriver,并打开webdriver
    driver = webdriver.Chrome(options=options)
    driver.get(url)

    # 获取文章标题,最后保存文件时使用该标题命名
    page_title = driver.find_element_by_tag_name('h2').text.strip().strip('\n\n').strip('\n')
    page_title = page_title.replace('?', "").replace('?', '').replace('.', '').replace('。', '')

    # ------------------------------------------------------------------------------------------------------------------
    # 以下为模拟键盘操作

    # 若网速较差时可以增加外循环次数,页面较长时增加内循环次数
    for quququ in range(2):
        print(quququ)
        for i in range(25):
            win32api.keybd_event(0x22, 0, 0, 0)  # 按下PAGE DOWN key
            win32api.keybd_event(0x22, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放PAGE DOWN
            print('\tPAGEDOWN' + str(i))
            time.sleep(random.random())
        print('\n')
        for i in range(25):
            win32api.keybd_event(0x21, 0, 0, 0)  # 按下PAGE UP key
            win32api.keybd_event(0x21, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放PAGE UP
            print('\tPAGEUP' + str(i))
            time.sleep(random.random())

    # 全选
    win32api.keybd_event(17, 0, 0, 0)  # 按下ctrl
    win32api.keybd_event(65, 0, 0, 0)  # 按下a
    win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放a
    win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放ctrl

    # 保存
    win32api.keybd_event(0x11, 0, 0, 0)  # 按下ctrl
    win32api.keybd_event(83, 0, 0, 0)  # 按下s
    win32api.keybd_event(83, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放s
    win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放ctrl
    time.sleep(random.randint(2, 4) / 10)

    # 切换输入法
    win32api.keybd_event(0x10, 0, 0, 0)  # 按下shift
    win32api.keybd_event(0x10, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放shift
    time.sleep(random.randint(2, 4) / 10)

    print('切换输入法,休息0.5秒')
    time.sleep(random.randint(1, 4) / 10)

    # 输入文件名 wj.mhtml
    win32api.keybd_event(0x57, 0, 0, 0)  # 按下w
    win32api.keybd_event(0x57, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放w
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x4A, 0, 0, 0)  # 按下j
    win32api.keybd_event(0x4A, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放j
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0xBE, 0, 0, 0)  # 按下英文句号
    win32api.keybd_event(0xBE, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放英文句号
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x4D, 0, 0, 0)  # 按下m
    win32api.keybd_event(0x4D, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放m
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x48, 0, 0, 0)  # 按下h
    win32api.keybd_event(0x48, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放h
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x54, 0, 0, 0)  # 按下t
    win32api.keybd_event(0x54, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放t
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x4D, 0, 0, 0)  # 按下m
    win32api.keybd_event(0x4D, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放m
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(0x4C, 0, 0, 0)  # 按下l
    win32api.keybd_event(0x4C, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放l
    time.sleep(random.randint(2, 4) / 10)

    # 切换输入法
    win32api.keybd_event(0x10, 0, 0, 0)  # 按下shift
    win32api.keybd_event(0x10, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放shift
    time.sleep(random.randint(2, 4) / 10)

    # alt + s 保存
    win32api.keybd_event(0x12, 0, 0, 0)  # 按下shift
    win32api.keybd_event(83, 0, 0, 0)  # 按下s
    time.sleep(random.randint(2, 4) / 10)

    win32api.keybd_event(83, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放s
    win32api.keybd_event(0x12, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放shift
    time.sleep(random.randint(2, 4) / 10)

    # 模拟操作结束
    # ------------------------------------------------------------------------------------------------------------------

    # # 预估保存页面弹出时间,后期根据实际网速调整
    # time.sleep(10)
    # win32api.keybd_event(13, 0, 0, 0)  # 按下enter
    # win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放enter
    # # 预估下载时间,后期根据实际网速调整
    inner_sleep_time = random.randint(5, 20)
    print('读取页面时休息,大约休息%ss,建议您将该时间修改为正常阅读一篇文章所需时间。' % inner_sleep_time)
    time.sleep(inner_sleep_time + random.random())
    # 关闭webdriver
    driver.close()

    # #old_add为我的电脑默认下载地址,这个地址需要根据具体情况修改
    # old_add = r'C:\Users\Administrator\Downloads\wj.mhtml'
    os.rename(r'C:\Users\Administrator\Downloads\wj.mhtml', r'C:\Users\Administrator\Downloads\%s.mhtml' % page_title)


def start_download():
    with open('bomblab.txt', 'r', encoding='utf-8') as file:
        link_lists = file.readlines()
        # print(link_lists)
        # print(len(link_lists))

        for index, item in enumerate(link_lists):
            try:
                print(index, item)
                if index % 10 == 0 and index != 0:
                    sleep_time = random.randint(120, 600)
                    print('大休息,时间是' + str(sleep_time) + '秒!')
                    time.sleep(random.random() + sleep_time)
                elif index % random.randint(2, 30) == 0:
                    sleep_time = random.randint(2, 10)
                    print('小休息,时间是' + str(sleep_time) + '秒!')
                    time.sleep(random.random() + sleep_time)
                else:
                    pass
                link = item.split('\t')[1]
                # title = item.split('\t')[0]
                download_single_spage(link)
            except:
                with open('error.txt', 'a+', encoding='utf-8') as file:
                    file.write(str(index))


if __name__ == '__main__':
    get_all_link()
    start_download()

最后获得部分结果如下:

purpose_pages.png

总结与回顾

  1. 本例还不太完整,未能全部获取;
  2. 缺少自动化、适应性差;
  3. 爬虫效率太低,应增加多进程以及分布式;
  4. 从开始动手到出结果总共耗时大概5小时;
  5. 恭喜小伙伴进入帕多瓦大学读博
  6. 意料之外又是意料之中。
上一篇 下一篇

猜你喜欢

热点阅读