简明需求

这里我先说一下需求:

从目标网站每隔一段时间爬取数据,并通过页面展示出来。

我们使用python3来爬取数据,使用flask进行页面展示。

目标数据如下:

码农之家

安装python3

这里使用的是python3.7.0,其它版本也是可以的,但一定是python3

开发工具

Python的开发工具一般会选择PyCharm来开发。

各位童鞋百度搜索PyCharm下载安装即可。

PyCharm最好破解激活一下,银子多的童鞋可以去支持一下正版,谢谢!

环境搭建

virtualenv

virtualenv 解决了什么问题?如果你像我一样喜欢 Python,不仅会在采用 Flask 的Web 应用中用上 virtualenv,在别的项目中你也会想用上它。你拥有的项目越多,同时使用不同版本的 Python 工作的可能性也就越大,或者起码需要不同版本的 Python 库。悲惨现实是:常常会有库破坏向后兼容性,然而正经应用不采用外部库的可能微乎其微。当在你的项目中,出现两个或更多依赖性冲突时,你会怎么做?

virtualenv 为每个不同项目提供一份 Python 安装。它并没有真正安装多个 Python 副本,但是它确实提供了一种巧妙的方式来让各项目环境保持独立。

表面上看virtualenv和docker的容器概念类似。

使用pip来进行安装,如果命令无效,请自行百度安装一下。

sudo pip install virtualenv

项目搭建

打开我们安装好的PyCharm,点击 Create New Project ,创建 flask 项目

码农之家

我们新建一个 virtualenv 环境,点击 Interpreter 右侧的 ··· ,选择 Create Virtualenv 点击 OK 然后 Create 创建项目。

码农之家

安装Flask

我们打开pycharm的终端,输入以下命令安装 Flask

pip install Flask

码农之家

几秒钟后,一切都搞定了。
在终端输入命令,启动 Flask

$ python pytt.py

码农之家

打开浏览器,输入 http://127.0.0.1:5000/ 可以看到如下界面说明安装成功。

码农之家

安装selenium

selenium可以让我们在后台模拟浏览器打开页面,并且获取网页渲染后源码,主要是解决由于javascript动态加载页面的问题。

安装命令

$ pip install selenium

用python写爬虫的时候,主要用的是selenium的Webdriver

Webdriver支持许多主流的浏览器比如火狐、谷歌等等,这里我们使用火狐的驱动,通过此驱动可以打开火狐浏览器并加载指定页面。

火狐的Webdriver驱动下载地址:https://github.com/mozilla/geckodriver/releases
这里我们下载 geckodriver-v0.24.0-macos.tar.gz

把gz文件减压后的 geckodriver 移动到前面创建的 virtualenv 环境下。

码农之家

安装 beautifulsoup4 和 lxml

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml

安装命令如下:

$ pip install beautifulsoup4
$ pip install lxml

安装 flask_apscheduler

flask_apscheduler 是 flask 下的一款定时器,方便好用。

$ pip install Flask-APScheduler

支持该安装的包基本完成,看似安装了好多包,其实就几个命令就搞定了。

重点来了,代码解析

先上项目结构图:

码农之家

  • data 存放过滤完的数据,这里放的是爬取的table
  • driver 火狐的驱动
  • log 系统运行日志
  • pages 爬取的页面的源码
  • static 静态文件,比如图片、css文件
  • templates 存放静态文件,用于页面展示
  • config.py 设置定时器相关的参数
  • jobs.py 爬取网页源码的核心代码
  • logging.conf 日志的配置文件
  • parse.py 解析爬取的页面源码,并进行清理
  • pytt.py 入口文件
  • requirements.txt 系统的依赖包

这里我们只讲几个核心的文件,整个项目可以去git获取

pytt.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from flask import Flask,render_template
from flask_apscheduler import APScheduler
from config import Config
import time
import logging
import logging.config
logging.config.fileConfig('logging.conf')


app = Flask(__name__)

'''定时器配置'''
app.config.from_object(Config()) 

@app.route('/jj.html')
def getjj():
    html = ''
    '''将解析的文件展示到页面上'''
    with open('./data/jj.txt','r') as o: 
        html = o.read()
        o.close()
    return render_template('jj.html',content=html,title='基金超市偏股型')


if __name__ == '__main__':

    '''定时器用法'''
    sche = APScheduler()
    sche.api_enabled = True
    sche.init_app(app)
    sche.start()
    app.run()

jobs.py

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import logging
from pytt import app
import parse

logger = logging.getLogger('job')

'''
执行定时任务
'''
def job():
    logger.debug('定时器开始执行')
    logger.debug('开始抓取数据')
    option = webdriver.FirefoxOptions()
    option.headless = True # 在后台运行火狐浏览器
    driver = webdriver.Firefox(options=option, service_log_path='./log/geckodriver.log')
    try:
        driver.get(app.config.get('URL')['jj']) # 打开指定链接
        WebDriverWait(driver, 10).until(
         '''直到id=tb_jjcs出现才抓取'''
            EC.visibility_of_element_located((By.ID, 'tb_jjcs'))
        )
        html = driver.page_source #页面源码
       '''保存页面'''
        with open('./pages/jj.html', 'w') as fb: 
            fb.write(html)
            fb.close()
            logger.debug('抓取天天基金网数据完成')
    except Exception as e:
        logger.error('失败!抓取天天基金网数据',exc_info=True)
    finally:
        driver.quit()
        logger.debug('开始解析所有抓取数据')
    parse.parst_jj()
    logger.debug('定时器开始完成')

parse.py

# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup
import logging
logger = logging.getLogger('job')


'''解析基金'''
def parst_jj():
    try:
        logger.debug('开始解析基金数据文件')
        file = open('./pages/jj.html')
        soup = BeautifulSoup(file,'lxml')
        table = soup(id='tb_jjcs')[0]
        thead_ths = table('th', text='操作')
        for th in thead_ths:
            th.decompose()  #去掉表格头中的操作
        tbody_tds = table('td',class_='widthBTN') 
        for td in tbody_tds:
            td.decompose() #去掉表格中的操作元素
        links = table('a')
        for link in links:
            del link['href'] #去掉a标签中链接
        table.tfoot.decompose() #去掉表格的tfoot
        #print(table.prettify())
        str = ''
       '''将清理后的table保存'''
        with open('./data/jj.txt','w') as fb:
            str += table.prettify()
            fb.write(str)
            fb.close()
        logger.debug('解析基金数据完成')
    except FileNotFoundError:
        logger.debug('解析基金数据文件失败,文件不存在')
    except Exception as e:
        logger.error('解析基金数据错误',exc_info=True)

结尾

如果童鞋们在使用过程中,遇到困难,可以直接在公众号留言。
公众号回复 pytt爬虫 获取完整代码

码农之家