Python个人博客程序开发实例框架设计

目录
  • 1.数据库(models.py)
    • 1.1 管理员 Admin
    • 1.2 分类 Category
    • 1.3 文章 Post
    • 1.4 评论 Comment
    • 1.5 社交链接 Link
  • 2.生成虚拟数据(fakes.py)
  • 3.模板
    • 3.1 模板上下文
    • 3.2 渲染导航链接
    • 3.3 Flash消息分类
  • 4.表单(forms.py)
    • 4.1 登录表单
    • 4.2 文章表单
    • 4.3 分类表单
    • 4.4 评论表单
  • 5.视图函数(blueprints:admin、auth、blog)
  • 6.电子邮件支持(emails.py)

本文要学习的示例程序是一个个人博客程序:Bluelog。博客是典型的 CMSContent Management System,内容管理系统),通常由两部分组成:一部分是博客前台,用来展示开放给所有用户的博客内容;另一部分是博客后台,这部分内容仅开放给博客管理员,用来对博客资源进行添加、修改和删除等操作。

1.数据库(models.py)

from datetime import datetime
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from bluelog.extensions import db

1.1 管理员 Admin

class Admin(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True) # 主键字段
    username = db.Column(db.String(20))          # 用户名
    password_hash = db.Column(db.String(128))    # 密码散列值
    blog_title = db.Column(db.String(60))        # 博客标题
    blog_sub_title = db.Column(db.String(100))   # 博客副标题
    name = db.Column(db.String(30))              # 用户姓名
    about = db.Column(db.Text)                   # 关于信息
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    def validate_password(self, password):
        return check_password_hash(self.password_hash, password)

1.2 分类 Category

class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)        # 主键字段
    name = db.Column(db.String(30), unique=True)        # 分类名称
    posts = db.relationship('Post', back_populates='category')  # 分类和文章之间是一对多关系
    def delete(self):
        default_category = Category.query.get(1)
        posts = self.posts[:]
        for post in posts:
            post.category = default_category
        db.session.delete(self)
        db.session.commit()

1.3 文章 Post

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)         # 主键字段
    title = db.Column(db.String(60))                     # 标题
    body = db.Column(db.Text)                            # 正文
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)  # 时间戳
    can_comment = db.Column(db.Boolean, default=True)    # 是否能被评论
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))   # 所属分类,外键字段
    category = db.relationship('Category', back_populates='posts')  # 分类和文章之间是一对多关系
    comments = db.relationship('Comment', back_populates='post', cascade='all, delete-orphan')  # 文章和评论是一对多关系

Comment 模型中创建的外键字段 post_id 存储 Post 记录的主键值。我们在这里设置了级联删除,也就是说,当某个文章记录被删除时,该文章所属的所有评论也会一并被删除,所以在删除文章时不用手动删除对应的评论。

1.4 评论 Comment

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)        # 主键字段
    author = db.Column(db.String(30))                   # 作者
    email = db.Column(db.String(254))                   # 电子邮件
    site = db.Column(db.String(255))                    # 站点
    body = db.Column(db.Text)                           # 正文
    from_admin = db.Column(db.Boolean, default=False)   # 是否是管理员的评论
    reviewed = db.Column(db.Boolean, default=False)     # 是否通过审核
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)  # 时间戳
    replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))   # 外键
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))         # 外键
    post = db.relationship('Post', back_populates='comments')         # 文章和评论是一对多关系
    replies = db.relationship('Comment', back_populates='replied', cascade='all, delete-orphan')  # 设置级联删除
    replied = db.relationship('Comment', back_populates='replies', remote_side=[id]) # 自关联多对一需用 remote_side=id 指定 ‘一' 的一方

博客程序中的评论要支持存储回复。我们想要为评论添加回复,并在获取某个评论时可以通过关系属性获得相对应的回复,这样就可以在模板中显示出评论之间的对应关系。那么回复如何存储在数据库中呢?

你当然可以再为回复创建一个 Reply 模型,然后使用一对多关系将评论和回复关联起来。但是我们将介绍一个更简单的解决办法,因为回复本身也是评论,如果可以在评论模型内建立层级关系,那么就可以在一个模型中表示评论和回复。

这种在同一个模型内的一对多关系在 SQLAlchemy 中被称为邻接列表关系(Adjacency List Relationship)。具体来说,我们需要在 Comment 模型中添加一个外键指向它自身。这样我们就得到一种层级关系:每个评论对象都可以包含多个子评论,即回复。

这个关系和我们之前熟悉的一对多关系基本相同。仔细回想一下一对多关系的设置,我们需要在 “多” 这一侧定义外键,这样 SQLAlchemy 就会知道哪边是 “多” 的一侧。这时关系对 “多” 这一侧来说就是多对一关系。但是在邻接列表关系中,关系的两侧都在同一个模型中,这时 SQLAlchemy 就无法分辨关系的两侧。在这个关系函数中,通过将 remote_side 参数设为 id 字段,我们就把 id 字段定义为关系的远程侧(Remote Side),而 replied_id 就相应地变为本地侧(Local Side),这样反向关系就被定义为多对一,即多个回复对应一个父评论。

集合关系属性 replies 中的 cascade 参数设为 all,因为我们期望的效果是,当父评论被删除时,所有的子评论也随之删除。

1.5 社交链接 Link

程序还包含了一个添加社交链接的功能。

class Link(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    url = db.Column(db.String(255))

2.生成虚拟数据(fakes.py)

from faker import Faker
fake = Faker()
def fake_admin():
def fake_categories(count=10):
def fake_posts(count=50):
def fake_links():

3.模板

3.1 模板上下文

在基模板的导航栏以及博客主页中需要使用博客的标题、副标题等存储在管理员对象上的数据,为了避免在每个视图函数中渲染模板时传入这些数据,我们在模板上下文处理函数中向模板上下文添加了管理员对象变量(admin)。另外,在多个页面中都包含的边栏中包含分类列表,我们也把分类数据传入到模板上下文中。

from bluelog.models import Admin, Category
def create_app(config_name=None):
    ...
	register_template_context(app)
	return app
def register_template_context(app):
    @app.context_processor
    def make_template_context():
    	admin = Admin.query.first()
        categories = Category.query.order_by(Category.name).all()
        return dict(admin=admin, categories=categories)

在基模板 base.html 和主页模板 index.html 中,我们可以直接使用传入的 admin 对象获取博客的标题和副标题。

<div class="page-header">
<h1 class="display-3">{{ admin.blog_title|default('Blog Title') }}</h1>
<h4 class="text-muted">&nbsp;{{ admin.blog_sub_title|default('Blog Subtitle') }}</h4>
</div>

3.2 渲染导航链接

导航栏上的按钮应该在对应的页面显示激活状态。举例来说,当用户单击导航栏上的 “关于” 按钮打开关于页面时,“关于” 按钮应该高亮显示。Bootstrap 为导航链接提供了一个 active 类来显示激活状态,我们需要为当前页面对应的按钮添加 active 类。

这个功能可以通过判断请求的端点来实现,对 request 对象调用 endpoint 属性即可获得当前的请求端点。如果当前的端点与导航链接指向的端点相同,就为它添加 active 类,显示激活样式。

<li {% if request.endpoint == 'blog.index' %}class="active"{% endif %}>
<a href="{{ url_for('blog.index') }}" rel="external nofollow" >Home</a>
</li>

有些教程中会使用 endswith() 方法来比较端点结尾。但是蓝本拥有独立的端点命名空间,即 “<蓝本名>.<端点名>”,不同的端点可能会拥有相同的结尾,比如 blog.indexauth.index,这时使用 endswith() 会导致判断错误,所以最妥善的做法是比较完整的端点值。

不过在 Bluelog 的模板中我们并没有使用这个 nav_link() 宏,因为 Bootstrap-Flask 提供了一个更加完善的 render_nav_item() 宏,它的用法和我们创建的 nav_link() 宏基本相同。这个宏可以在模板中通过 bootstrap/nav.html 路径导入,它支持的常用参数如下表所示。

3.3 Flash消息分类

我们目前的 Flash 消息应用了 Bootstrap 的 alert-info 样式,单一的样式使消息的类别和等级难以区分,更合适的做法是为不同类别的消息应用不同的样式。比如,当用户访问出错时显示一个黄色的警告消息;而普通的提示信息则使用蓝色的默认样式。Bootstrap 为提醒消息(Alert)提供了 8 种基本的样式类,即 alert-primaryalert-secondaryalert-successalert-dangeralert-warningalert-lightalert-dark

要开启消息分类,我们首先要在消息渲染函数 get_flashed_messages 中将 with_categories 参数设为 True。这时会把消息迭代为一个类似于(分类,消息)的元组,我们使用消息分类字符来构建样式类。

<main class="container">
	{% for message in get_flashed_messages(with_categories=True) %}
	<div class="alert alert-{{ message[0] }}" role="alert">
		<button type="button" class="close" data-dismiss="alert">&times;</button>
		{{ message[1] }}
	</div>
	{% endfor %}
	...
</main>

4.表单(forms.py)

Bluelog 中主要包含下面这些表单:登录表单、文章表单、分类表单、评论表单、博客设置表单。这里我们仅介绍登录表单、文章表单、分类表单和评论表单,其他的表单在实现上基本相同,不再详细介绍。

删除资源也需要使用表单来实现,这里之所以没有创建表单类,是因为后面我们会介绍在实现删除操作时为表单实现 CSRF 保护的更方便的做法,届时表单可以手动在模板中写出。

4.1 登录表单

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
    password = PasswordField('Password', validators=[DataRequired(), Length(1, 128)])
    remember = BooleanField('Remember me')
    submit = SubmitField('Log in')

登录表单由用户名字段 username、密码字段 password、“记住我” 复选框 remember 和 “提交” 按钮 submit 组成。

4.2 文章表单

from flask_ckeditor import CKEditorField
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField
from wtforms.validators import DataRequired, Length
from bluelog.models import Category
class PostForm(FlaskForm):
    title = StringField('Title', validators=[DataRequired(), Length(1, 60)])
    category = SelectField('Category', coerce=int, default=1)
    body = CKEditorField('Body', validators=[DataRequired()])
    submit = SubmitField()
    def __init__(self, *args, **kwargs):
        super(PostForm, self).__init__(*args, **kwargs)
        self.category.choices = [(category.id, category.name)
                                 for category in Category.query.order_by(Category.name).all()]

文章创建表单由标题字段 title、分类选择字段 category、正文字段 body 和 “提交” 按钮组成,其中正文字段使用 Flask-CKEditor 提供的 CKEditorField 字段。

下拉列表字段使用 WTForms 提供的 SelectField 类来表示 HTML 中的 标签。下拉列表的选项(即 标签)通过参数 choices 指定。choices 必须是一个包含两元素元组的列表,列表中的元组分别包含选项值和选项标签。我们使用分类的 id 作为选项值,分类的名称作为选项标签,这两个值通过迭代 Category.query.order_by(Category.name).all() 返回的分类记录实现。选择值默认为字符串类型,我们使用 coerce 关键字指定数据类型为整型。default 用来设置默认的选项值,我们将其指定为 1,即默认分类的 id

因为 Flask-SQLAlchemy 依赖于程序上下文才能正常工作(内部使用 current_app 获取配置信息),所以这个查询调用要放到构造方法中执行,在构造方法中对 self.category.choices 赋值的效果和在类中实例化 SelectField 类并设置 choices 参数相同。

4.3 分类表单

from wtforms import StringField, SubmitField, ValidationError
from wtforms import DataRequired
from bluelog.models import Category
class CategoryForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(1, 30)])
    submit = SubmitField()
    def validate_name(self, field):
        if Category.query.filter_by(name=field.data).first():
            raise ValidationError('Name already in use.')

分类创建字段仅包含分类名称字段(name)和提交字段。分类的名称要求不能重复,为了避免写入重复的分类名称导致数据库出错,我们在 CategoryForm 类中添加了一个 validate_name 方法,作为 name 字段的自定义行内验证器,它将在验证 name 字段时和其他验证函数一起调用。在这个验证方法中,我们使用字段的值 filed.data 作为 name 列的参数值进行查询,如果查询到已经存在同名记录,那么就抛出 ValidationError 异常,传递错误消息作为参数。

4.4 评论表单

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Email, URL, Length, Optional
class CommentForm(FlaskForm):
    author = StringField('Name', validators=[DataRequired(), Length(1, 30)])
    email = StringField('Email', validators=[DataRequired(), Email(), Length(1, 254)])
    site = StringField('Site', validators=[Optional(), URL(), Length(0, 255)])
    body = TextAreaField('Comment', validators=[DataRequired()])
    submit = SubmitField()

在这个表单中,email 字段使用了用于验证电子邮箱地址的 Email 验证器。另外,因为评论者的站点是可以留空的字段,所以我们使用 Optional 验证器来使字段可以为空。site 字段使用 URL 验证器确保输入的数据为有效的 URL

和匿名用户的表单不同,管理员不需要填写诸如姓名、电子邮箱等字段。我们单独为管理员创建了一个表单类,这个表单类继承自 CommentForm 类。

class AdminCommentForm(CommentForm):
    author = HiddenField()
    email = HiddenField()
    site = HiddenField()

在这个表单中,姓名、Email、站点字段使用 HiddenField 类重新定义。这个类型代表隐藏字段,即 HTML 中的 < input type=“hidden” >。

5.视图函数(blueprints:admin、auth、blog)

在上面我们已经创建了所有必须的模型类、模板文件和表单类。经过程序规划和设计后,我们可以创建大部分视图函数。这些视图函数暂时没有实现具体功能,仅渲染对应的模板,或是重定向到其他视图。以 blog 蓝本为例。

from flask import render_template, Blueprint
blog_bp = Blueprint('blog', __name__)
@blog_bp.route('/')
def index():
	return render_template('blog/index.html')
@blog_bp.route('/about')
def about():
	return render_template('blog/about.html')
@blog_bp.route('/category/<int:category_id>')
def show_category(category_id):
	return render_template('blog/category.html')
@blog_bp.route('/post/<int:post_id>', methods=['GET', 'POST'])
def show_post(post_id):
	return render_template('blog/post.html')

blog 蓝本类似,我们在 blueprints 子包中创建了 auth.pyadmin.py 脚本,这些脚本中分别创建了 authadmin 蓝本,蓝本实例的名称分别为 auth_bpadmin_bp

6.电子邮件支持(emails.py)

因为博客要支持评论,所以我们需要在文章有了新评论后发送邮件通知管理员。而且,当管理员回复了读者的评论后,也需要发送邮件提醒读者。

因为邮件的内容很简单,我们将直接在发信函数中写出正文内容,这里只提供了 HTML 正文。我们有两个需要使用电子邮件的场景:

  • 当文章有新评论时,发送邮件给管理员;
  • 当某个评论被回复时,发送邮件给被回复用户。

为了方便使用,我们在 emails.py 中分别为这两个使用场景创建了特定的发信函数,可以直接在视图函数中调用。这些函数内部则通过调用我们创建的通用发信函数 send_mail() 来发送邮件。

from flask import url_for
def send_mail(subject, to, html):
	...
def send_new_comment_email(post):
    post_url = url_for('blog.show_post', post_id=post.id, _external=True) + '#comments'
    send_mail(subject='New comment', to=current_app.config['BLUELOG_EMAIL'],
              html='<p>New comment in post <i>%s</i>, click the link below to check:</p>'
                   '<p><a href="%s" rel="external nofollow"  rel="external nofollow" >%s</a></P>'
                   '<p><small style="color: #868e96">Do not reply this email.</small></p>'
                   % (post.title, post_url, post_url))

send_new_comment_email() 函数用来发送新评论提醒邮件。我们通过将 url_for() 函数的 _external 参数设为 True 来构建外部链接。链接尾部的 #comments 是用来跳转到页面评论部分的URL片段(URL fragment),comments 是评论部分 div 元素的 id 值。这个函数接收表示文章的 post 对象作为参数,从而生成文章正文的标题和链接。

URL 片段又称片段标识符(fragment identifier),是 URL 中用来标识页面中资源位置的短字符,以 # 开头,对于 HTML 页面来说,一个典型的示例是文章页面的评论区。假设评论区的 div 元素 idcomment,如果我们访问 http://example.com/post/7#comment,页面加载完成后将会直接跳到评论部分。

def send_new_reply_email(comment):
    post_url = url_for('blog.show_post', post_id=comment.post_id, _external=True) + '#comments'
    send_mail(subject='New reply', to=comment.email,
              html='<p>New reply for the comment you left in post <i>%s</i>, click the link below to check: </p>'
                   '<p><a href="%s" rel="external nofollow"  rel="external nofollow" >%s</a></p>'
                   '<p><small style="color: #868e96">Do not reply this email.</small></p>'
                   % (comment.post.title, post_url, post_url))

send_new_reply_email() 函数则用来发送新回复提醒邮件。这个发信函数接收 comment 对象作为参数,用来构建邮件正文,所属文章的主键值通过 comment.post_id 属性获取,标题则通过 comment.post.title 属性获取。

在 Bluelog 源码中,我们没有使用异步的方式发送邮件,如果你希望编写一个异步发送邮件的通用发信函数 send_mail(),可以使用以下方式。

from threading import Thread
from flask import current_app
from flask_mail import Message
from bluelog.extensions import mail
def _send_async_mail(app, message):
    with app.app_context():
        mail.send(message)
def send_mail(subject, to, html):
    app = current_app._get_current_object()
    message = Message(subject, recipients=[to], html=html)
    thr = Thread(target=_send_async_mail, args=[app, message])
    thr.start()
    return thr

需要注意的是,因为我们的程序实例是通过工厂函数构建的,所以实例化 Thread 类时,我们使用代理对象 current_app 作为 args 参数列表中 app 的值。另外,因为在新建的线程时需要真正的程序对象来创建上下文,所以我们不能直接传入 current_app,而是传入对 current_app 调用 _get_current_object() 方法获取到的被代理的程序实例。

到此这篇关于Python个人博客程序开发实例框架设计的文章就介绍到这了,更多相关Python个人博客内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python个人博客程序开发实例后台编写

    目录 1.文章管理 1.1 文章管理主页 1.2 创建文章 1.3 编辑与删除 2.评论管理 2.1 关闭评论 2.2 评论审核 2.3 筛选评论 3.分类管理 本篇博客将是Python个人博客程序开发实例的最后一篇.本篇文章将会详细介绍博客后台的编写. 为了支持管理员管理文章.分类.评论和链接,我们需要提供后台管理功能.通常来说,程序的这一部分被称为管理后台.控制面板或仪表盘等.这里通常会提供网站的资源信息和运行状态,管理员可以统一查看和管理所有资源.管理员面板通常会使用独立样式的界面,所以你

  • Python个人博客程序开发实例用户验证功能

    目录 1.安全存储密码 2.使用Flask-Login管理用户认证 2.1 获取当前用户 2.2 登入用户 2.3 登出用户 2.4 视图保护 3.使用CSRFProtect实现CSRF保护 在Python个人博客程序开发实例框架设计中,我们已经完成了 数据库设计.数据准备.模板架构.表单设计.视图函数设计.电子邮件支持 等总体设计的内容. 在Python个人博客程序开发实例信息显示中,我们一起实现了 显示文章列表.博客信息.文章内容和评论 等功能. 那么,本篇文章将会介绍如何 初始化博客.利用

  • Python个人博客程序开发实例框架设计

    目录 1.数据库(models.py) 1.1 管理员 Admin 1.2 分类 Category 1.3 文章 Post 1.4 评论 Comment 1.5 社交链接 Link 2.生成虚拟数据(fakes.py) 3.模板 3.1 模板上下文 3.2 渲染导航链接 3.3 Flash消息分类 4.表单(forms.py) 4.1 登录表单 4.2 文章表单 4.3 分类表单 4.4 评论表单 5.视图函数(blueprints:admin.auth.blog) 6.电子邮件支持(email

  • Python个人博客程序开发实例信息显示

    目录 1.分页显示文章列表 1.1 获取分页记录 1.2 渲染分页导航部件 2.显示文章正文 3.文章固定链接 4.显示分类文章列表 5.显示评论列表 6.发表评论与回复 7.支持回复评论 8.网站主题切换 Python个人博客程序开发实例框架设计中,我们已经完成了 数据库设计.数据准备.模板架构.表单设计.视图函数设计.电子邮件支持 等总体设计的内容,本篇博客将介绍博客前台的实现.博客前台需要开放给所有用户,这里包括 显示文章列表.博客信息.文章内容和评论 等功能. 1.分页显示文章列表 为了

  • Python初学时购物车程序练习实例(推荐)

    废话不多说,直接上代码 #Author:Lancy Wu product_list=[ ('Iphone',5800), ('Mac Pro',9800), ('Bike', 800), ('Watch', 10600), ('Coffee', 31), ('Lancy Python', 120) ] #商品列表 shopping_list=[] #定义一个列表来存储已购商品 salary=input("请输入工资:") if salary.isdigit(): #当输入的内容为数字

  • Python简单基础小程序的实例代码

    1 九九乘法表 for i in range(9):#从0循环到8 i += 1#等价于 i = i+1 for j in range(i):#从0循环到i j += 1 print(j,'*',i,'=',i*j,end = ' ',sep='') # end默认在结尾输出换行,将它改成空格 sep 默认 j,'*',i,'=',i*j 各元素输出中间会有空格 print()#这里作用是输出换行符 i = 1 while i <= 9: j = 1 while j <= i: print(&

  • python打开windows应用程序的实例

    可以加上时间判断,让程序在固定的时间启动. #coding=utf-8 #!/usr/bin/python import os def open_app(app_dir): os.startfile(app_dir) if __name__ == "__main__": app_dir = r'C:\Program Files\Sublime Text 2\sublime_text.exe' open_app(app_dir) 以上这篇python打开windows应用程序的实例就是小

  • 基于Python+QT的gui程序开发实现

    最近帮朋友做了一个将文本文件按条件导出到excel里面的小程序.使用了PyQT,发现Python真是一门强大的脚本语言,开发效率极高. 首先需要引用 from PyQt4 import QtGui, uic, QtCore 很多控件像QPushButton是从QtGui的空间中得来的,下面def __init__(self, parent=None)中定义了界面的设计及与控件相互联系的方法. class AddressBook(QtGui.QWidget): def __init__(self,

  • Python实现博客快速备份的脚本分享

    目录 转存文章到MD 转存图片到本地 鉴于有些小伙伴在寻找博客园迁移到个人博客的方案,本人针对博客园实现了一个自动备份脚本,可以快速将博客园中自己的文章备份成Markdown格式的独立文件,备份后的md文件可以直接放入到hexo博客中,快速生成自己的站点,而不需要自己逐篇文章迁移,提高了备份文章的效率. 首先第一步将博客园主题替换为codinglife默认主题,第二步登录到自己的博客园后台,然后选择博客备份,备份所有的随笔文章,如下所示: 备份出来以后将其命名为backup.xml,然后新建一个

  • Python 自动刷博客浏览量实例代码

    思路来源 今天很偶然的一个机会,听到别人在谈论现在的"刷量"行为,于是就激发了我的好奇心.然后看了下requests模块正好对我有用,就写了一个简单的测试用例.神奇的发现这一招竟然是管用的.那还等什么,开刷咯. 前奏 思路很简单,就是一个发送请求的实现,就可以了.代码如下: headers = { 'referer':'http://jb51.net/', 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537

  • 使用Python实现博客上进行自动翻页

    先上一张代码及代码运行后的输出结果的图! 下面上代码: # coding=utf-8 import os import time from selenium import webdriver #打开火狐浏览器 需要V47版本以上的 driver = webdriver.Firefox()#打开火狐浏览器 url = "http://codelife.ecit-it.com"#这里打开我的博客网站 driver.get(url)#设置火狐浏览器打开的网址 time.sleep(2) #使

随机推荐