Vue2前后端分离项目SSR优化SEO(基于Python)
Vue2前后端分离项目SSR优化SEO(基于Python)
#### 搜索引擎爬取机制
类似普通爬虫,不会加载js文件,如果内容是动态加载则无法获取真实内容
#### 解决方案
1、SSG静态站点(不适用,pass)
2、SSR服务端渲染
#### 实现SSR的方式
传统可以自己在前端项目中建一个服务器,或者使用框架(Nuxt.js)。这种会有一个问题,那就是特定于客户端的功能无法使用,但是我的项目又有许多这种东西,且使用Nuxt.js需要重构整个项目,实在不现实。
#### 替代方案
我们基于自建服务器的思想,可以自建一个服务器来专门针对搜索引擎来反馈真实数据,同时对于客户端的请求则不通过这个服务器,这样也可以大大减轻服务器压力。
这个时候我们会想到通过服务器将url真实的数据请求得到后返回给搜索引擎,同时在服务器上做好流量转发。这时服务器语言我们选择Python,因为方便。
#### 流量转发
我们可以通过修改nignx配置来实现
```shell
# 定义非客户端请求的特征(包括搜索引擎、爬虫、API请求工具等)
set $is_non_client false;
# 匹配常见的爬虫、bot和工具的User-Agent
if ($http_user_agent ~* "Googlebot|Bingbot|BaiduSpider|Spider|Crawler|bot|Slurp|Mediapartners|AdsBot|bingbot|google-PageRenderer|googleweblightcrawler|googlebot-mobile|googlebot-image|Googlebot-Image|Googlebot-Video|Googlebot-Mobile|Google Web Preview|googleweblight|Googlebot|Google-PageRenderer|Googlebot/2.1|Google-PageRenderer/1.0|Googlebot/1.0|Googlebot-Mobile/1.0|curl|Postman|HTTPie|Unirest|python-requests|Java|okhttp|Apache-HttpClient|libcurl|libcurl|libcurl/|libcurl/|curl/|curl/|wget|HTTPClient|HTTP/1.1|HTTP/1.0|HTTP/2.0|HTTP/1.1|HTTP/1.1|PostmanRuntime-ApipostRuntime/1.1.0") {
set $is_non_client true;
}
location /article {
# 如果是非客户端请求,转发到另一个URL
if ($is_non_client = true) {
#return 200 "$request_uri";
proxy_pass https://exmaple.com$request_uri;
}
# 处理正常请求的静态文件
try_files $uri $uri/ /index.html;
}
location / {
# 处理正常请求的静态文件
try_files $uri $uri/ /index.html;
}
```
这样我们可以将搜索引擎的流量转发到https://exmaple.com$request_uri中,再使其返回真实数据就可以了。
#### 服务端
我们可以使用**selenium**来模拟浏览器从而获取真实数据
```python
import time
from flask import Flask
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
from bs4 import BeautifulSoup
app = Flask(__name__)
driver_path = "/usr/local/bin/geckodriver"
# 配置无头模式
options = Options()
options.add_argument('--headless') # 无头模式
options.add_argument('--no-sandbox') # 禁用沙盒模式(Linux上必需)
options.add_argument('--disable-gpu') # 禁用GPU加速
options.add_argument('--disable-dev-shm-usage') # 禁用共享内存
options.binary_location = "/usr/bin/firefox"
driver_path = Service(executable_path=driver_path)
# 初始化WebDriver
driver = webdriver.Firefox(service=driver_path, options=options)
@app.route("/article/<id>", methods=["GET"])
def tvm(id):
try:
url = 'https://exmaple.com/' + id #替换为自己前端真实地址
driver.get(url)
# 等待JavaScript执行完成(根据实际情况调整等待时间)
time.sleep(5)
# 获取页面源码
html = driver.page_source
# 解析HTML内容
soup = BeautifulSoup(html, 'html.parser')
return str(soup)
except Exception as e:
print(f"发生错误:{e}")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000, debug=True)
```
这样可以获取到真是的内容,可是我们服务器资源有限,开启浏览器会消耗较多资源,且时间较久。这时候我们会想到我们只需要要返回真实数据就可以了,无需在意其他,那么我们可以直接去连接数据库,获取所需要的内容再按照html形式返回就可以了,当然也可以直接请求后端接口来获取数据,这里我为了减轻后端服务器压力就不采用。
#### 优化
```python
import mysql.connector
from flask import Flask,render_template_string
# 连接到数据库
conn = mysql.connector.connect(
user='root',
password='root',
host='127.0.0.1',
database='database'
)
query = "SELECT article_title, article_content, view_count, update_by FROM article WHERE id = %s AND deleted = 0"
cursor = conn.cursor()
str = """
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{keywords}}</title>
<meta content="{{keywords}}" name="keywords"/>
<meta content="文章浏览阅读{{count}}次。{{description}}" name="description"/>
<meta content="{{author}}" name="author"/>
<link href="https://api.timeplanet.cn/documents/article/{{id}}" rel="canonical"/>
</head>
<body>
<h1 style="display: none;">
{{keywords}}
</h1>
<div class="article-title" data-v-54aad278="">
{{keywords}}
</div>
<div>
{{body}}
</div>
</body>
</html>
"""
app = Flask(__name__)
@app.route("/article/<id>", methods=["GET"])
def tvm(id):
cursor.execute(query, (id,))
rows = cursor.fetchall()
data = {
'keywords': rows[0][0],
'description': rows[0][1],
'author': rows[0][3],
'body': rows[0][1],
'id': id,
'count': rows[0][2]
}
return render_template_string(str,**data)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000, debug=True)
```
#### 完结撒花
到这里我们就完成了SSR的搭建了,对于那种项目不方便迁移的,客户端特定功能使用过多的项目是是十分的友好。