增加新项目
This commit is contained in:
23
项目合集/最新写真app/backend/ .gitignore
Normal file
23
项目合集/最新写真app/backend/ .gitignore
Normal file
@@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
15
项目合集/最新写真app/backend/.drone.yml
Normal file
15
项目合集/最新写真app/backend/.drone.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
clone:
|
||||
disable: true
|
||||
|
||||
steps:
|
||||
- name: myclone
|
||||
image: 2271608011/bmygit:v1.2
|
||||
network_mode: host
|
||||
commands:
|
||||
- echo "192.168.31.100 git.buyusdt.xyz" >> /etc/hosts
|
||||
- git clone https://git.buyusdt.xyz/bmy/xiezheng.git
|
||||
- cd /drone/src/xiezheng/ && npm install && npm run dev && npm run log
|
||||
67
项目合集/最新写真app/backend/app.js
Normal file
67
项目合集/最新写真app/backend/app.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import express from "express";
|
||||
import config from "./config/config.js";
|
||||
import { ipv6, ipv4 } from "./utils/ip.js";
|
||||
|
||||
import tagsRouter from "./router/tags.js";
|
||||
import infoRouter from "./router/info.js";
|
||||
import searchRouter from "./router/search.js";
|
||||
import homeRouter from "./router/home.js";
|
||||
import hotRouter from "./router/hot.js";
|
||||
import http from "http";
|
||||
|
||||
const app = express()
|
||||
|
||||
//解决跨域
|
||||
app.use((req, res, next) => {
|
||||
// 设置是否运行客户端设置 withCredentials
|
||||
// 即在不同域名下发出的请求也可以携带 cookie
|
||||
res.header("Access-Control-Allow-Credentials", true)
|
||||
// 第二个参数表示允许跨域的域名,* 代表所有域名
|
||||
res.header('Access-Control-Allow-Origin', '*')//配置80端口跨域
|
||||
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, OPTIONS') // 允许的 http 请求的方法
|
||||
// 允许前台获得的除 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 这几张基本响应头之外的响应头
|
||||
res.header('Access-Control-Allow-Headers', '*')
|
||||
if (req.method == 'OPTIONS') {
|
||||
res.sendStatus(200)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
app.use('/v1/api/tag', tagsRouter);
|
||||
app.use('/v1/api/info', infoRouter);
|
||||
app.use('/v1/api/search', searchRouter);
|
||||
app.use('/v1/api/home', homeRouter);
|
||||
app.use('/v1/api/hot', hotRouter);
|
||||
|
||||
http.createServer(app).listen(config.port, "::",() => {
|
||||
console.log(`
|
||||
爬虫运行在下面网址:
|
||||
|
||||
1️⃣ 公网 IPV6: http://[${ipv6()}]:${config.port}
|
||||
2️⃣ 局域网 IPV4: http://${ipv4()}:${config.port}
|
||||
|
||||
`)
|
||||
})
|
||||
|
||||
// error handler
|
||||
app.use(function(err, req, res, next) {
|
||||
console.log(`
|
||||
程序出现错误
|
||||
status信息为:${err.status}
|
||||
message信息为:${err.message}
|
||||
error为:${err}
|
||||
`)
|
||||
});
|
||||
|
||||
// app.listen(config.port, () => {
|
||||
// console.log(`
|
||||
// 爬虫运行在下面网址:
|
||||
|
||||
// 1️⃣ 公网 IPV6: http://[${ipv6()}]:${config.port}
|
||||
// 2️⃣ 局域网 IPV4: http://${ipv4()}:${config.port}
|
||||
// `)
|
||||
// })
|
||||
|
||||
|
||||
export default app
|
||||
8
项目合集/最新写真app/backend/config/config.js
Normal file
8
项目合集/最新写真app/backend/config/config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export default {
|
||||
port: 9940,
|
||||
proxyPort: 7890,
|
||||
baseUrl: 'https://www.06se.com',
|
||||
hot_tags: function () {
|
||||
return `${this.baseUrl}/hot_tags`
|
||||
}
|
||||
}
|
||||
2515
项目合集/最新写真app/backend/package-lock.json
generated
Normal file
2515
项目合集/最新写真app/backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
项目合集/最新写真app/backend/package.json
Normal file
25
项目合集/最新写真app/backend/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "newbackapi",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "./node_modules/.bin/pm2 start app.js --stop-exit-codes 0",
|
||||
"stop": "./node_modules/.bin/pm2 stop app",
|
||||
"log": "./node_modules/.bin/pm2 log",
|
||||
"list": "./node_modules/.bin/pm2 list",
|
||||
"monit": "pm2 monit"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"express": "^4.21.1",
|
||||
"https-proxy-agent": "^7.0.5",
|
||||
"ip": "^2.0.1",
|
||||
"pm2": "^5.4.3"
|
||||
}
|
||||
}
|
||||
78
项目合集/最新写真app/backend/router/home.js
Normal file
78
项目合集/最新写真app/backend/router/home.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import express from "express";
|
||||
import Util from '../utils/index.js'
|
||||
import Config from '../config/config.js'
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 获取首页banner图
|
||||
// http://192.168.31.101:9940/v1/api/home/banner
|
||||
router.get('/banner', async (req, res) => {
|
||||
// let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
|
||||
// $(".new-swiper .swiper-wrapper .swiper-slide").each(function() {
|
||||
// let src = $(this).find("span img").attr("src")
|
||||
// console.log("src: ", src);
|
||||
// if (src) {
|
||||
// result.push({ src })
|
||||
// }
|
||||
// })
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: [
|
||||
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/54e736d12f2eb938b7ce5c2990628535e4dd6f4d.jpg' },
|
||||
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/b899a9014c086e06d533199047087bf40bd1cb56.jpg' },
|
||||
{ src: 'https://image.baidu.com/search/down?thumburl=https://baidu.com&url=https://imgsa.baidu.com/forum/pic/item/269759ee3d6d55fb6c5d50fd28224f4a21a4dd56.jpg' },
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
// 获取热门推荐的写真
|
||||
// http://192.168.31.101:9940/v1/api/home/hot
|
||||
router.get('/hot', async (req, res) => {
|
||||
let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
|
||||
let result = []
|
||||
|
||||
$(".box-body .tab-content .posts-mini").each(function() {
|
||||
result.push({
|
||||
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
|
||||
title: $(this).find(".item-heading a").text(),
|
||||
time: $(this).find(".item-meta .icon-circle").text(),
|
||||
view: $(this).find(".item-meta .meta-right .meta-view").text()
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// 获取首页 默认的随机写真
|
||||
// http://192.168.31.101:9940/v1/api/home/list
|
||||
router.get('/list', async (req, res) => {
|
||||
let $ = await Util.get(`${Config.baseUrl}/?orderby=rand`)
|
||||
let result = []
|
||||
|
||||
$(".tab-content .posts-row .posts-item").each(function() {
|
||||
result.push({
|
||||
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
|
||||
title: $(this).find(".item-heading a").text(),
|
||||
time: $(this).find(".item-meta .icon-circle").text(),
|
||||
view: $(this).find(".item-meta .meta-right .meta-view").text()
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
export default router
|
||||
40
项目合集/最新写真app/backend/router/hot.js
Normal file
40
项目合集/最新写真app/backend/router/hot.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import express from "express";
|
||||
import Util from '../utils/index.js'
|
||||
import Config from '../config/config.js'
|
||||
import utils from "../utils/index.js";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 获取 底部导航的 热门
|
||||
// http://192.168.31.101:9940/v1/api/hot/list?page=1
|
||||
router.get('/list', async (req, res) => {
|
||||
let { page } = req.query
|
||||
page = page || 1
|
||||
|
||||
let $ = await Util.get(`${Config.baseUrl}/other/page/${page}`)
|
||||
|
||||
let result = {
|
||||
currentPage: page,
|
||||
totalPage: utils.maxPage(".pagenav a", $),
|
||||
message: $(".search-content .badg .focus-color").text(),
|
||||
list: [],
|
||||
}
|
||||
|
||||
$(".posts-row .posts-item").each(function() {
|
||||
result.list.push({
|
||||
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
|
||||
title: $(this).find(".item-heading a").text(),
|
||||
time: $(this).find(".item-meta .icon-circle").text(),
|
||||
view: $(this).find(".item-meta .meta-right .meta-view").text()
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
})
|
||||
|
||||
export default router
|
||||
42
项目合集/最新写真app/backend/router/info.js
Normal file
42
项目合集/最新写真app/backend/router/info.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import express from "express";
|
||||
import Util from '../utils/index.js'
|
||||
import Config from '../config/config.js'
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 进入详情的接口
|
||||
// http://192.168.31.101:9940/v1/api/info/list?id=6808
|
||||
router.get('/list', async (req, res) => {
|
||||
let { id } = req.query
|
||||
let $ = await Util.get(`${Config.baseUrl}/${id}.html`)
|
||||
let result = {
|
||||
title: $(".article .article-header .article-title a").text(),
|
||||
src_list: [],
|
||||
recommend: [],
|
||||
}
|
||||
|
||||
$(".article-content .wp-posts-content p img").map(function(i, el) {
|
||||
result.src_list.push($(el).attr("data-src"))
|
||||
})
|
||||
|
||||
$(".swiper-container .swiper-slide a").each(function(i, el) {
|
||||
result.recommend.push({
|
||||
id: Util.split($(this).attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find("img").attr("data-src"),
|
||||
title: $(this).find(".text-ellipsis").text(),
|
||||
time: $(this).find(".px12 item").eq(0).text(),
|
||||
view: $(this).find(".px12 item").eq(1).text(),
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
export default router
|
||||
70
项目合集/最新写真app/backend/router/search.js
Normal file
70
项目合集/最新写真app/backend/router/search.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import express from "express";
|
||||
import Util from '../utils/index.js'
|
||||
import Config from '../config/config.js'
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 搜索页面的 热门关键词 & 推荐
|
||||
// http://192.168.31.101:9940/v1/api/search/hot
|
||||
router.get('/hot', async (req, res) => {
|
||||
let $ = await Util.get(`${Config.baseUrl}/wp-admin/admin-ajax.php?action=search_box`)
|
||||
let result = {
|
||||
hotKeyword: [],
|
||||
recommend: []
|
||||
}
|
||||
|
||||
$(".search-input .search-keywords").eq(0).find("div a").each(function() {
|
||||
result.hotKeyword.push($(this).text())
|
||||
})
|
||||
|
||||
$(".search-input .relates-thumb .swiper-slide a").each(function() {
|
||||
result.recommend.push({
|
||||
id: Util.split($(this).attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find("img").attr("data-src"),
|
||||
title: $(this).find(".text-ellipsis").text(),
|
||||
time: $(this).find(".px12 item").eq(0).text(),
|
||||
view: $(this).find(".px12 item").eq(1).text(),
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// 搜索接口
|
||||
// http://192.168.31.101:9940/v1/api/search/key?keyword=杨晨晨&page=1
|
||||
router.get('/key', async (req, res) => {
|
||||
let { keyword, page } = req.query
|
||||
page = page || 1
|
||||
|
||||
let $ = await Util.get(`${Config.baseUrl}/page/${page}?s=${encodeURI(keyword)}&type=post`)
|
||||
let result = {
|
||||
currentPage: page,
|
||||
totalPage: Util.maxPage(".pagenav a", $),
|
||||
message: $(".search-content .badg .focus-color").text(),
|
||||
list: [],
|
||||
}
|
||||
|
||||
$(".search-content .posts-item").each(function() {
|
||||
result.list.push({
|
||||
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
|
||||
title: $(this).find(".item-body .item-heading a").text(),
|
||||
time: $(this).find(".item-body .item-meta .icon-circle").text(),
|
||||
view: $(this).find(".item-body .item-meta .meta-right .meta-view").text()
|
||||
})
|
||||
})
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
export default router
|
||||
76
项目合集/最新写真app/backend/router/tags.js
Normal file
76
项目合集/最新写真app/backend/router/tags.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import express from "express";
|
||||
import Util from '../utils/index.js'
|
||||
import Config from '../config/config.js'
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 获取 推荐标签
|
||||
// http://192.168.31.101:9940/v1/api/tag/recommend
|
||||
router.get('/recommend', async (req, res) => {
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: [
|
||||
{ title: '秀人网', count: '9059', url: '/xiuren', index: 0 },
|
||||
{ title: 'ROSI写真', count: '6580', url: '/domestic/rosi', index: 2 },
|
||||
{ title: '蜜桃社', count: '122', url: '/domestic/miitao', index: 27 },
|
||||
{ title: '尤物馆', count: '138', url: '/domestic/youwu', index: 29 },
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
// 获取 所有标签
|
||||
// http://192.168.31.101:9940/v1/api/tag/list
|
||||
router.get('/list', async (req, res) => {
|
||||
let $ = await Util.get(Config.hot_tags())
|
||||
let result = []
|
||||
$(".categorieslist ul li a").each(function (i) {
|
||||
result.push({
|
||||
title: $(this).find("h2").text(),
|
||||
count: $(this).find("small p").text().replace(/[^\d]/g, ""),
|
||||
url: Util.split($(this).attr("href")),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
});
|
||||
})
|
||||
|
||||
// 进入对应标签的列表页面
|
||||
// http://192.168.31.101:9940/v1/api/tag/info?url=/xiuren&page=1
|
||||
router.get('/info', async (req, res) => {
|
||||
let { url, page } = req.query
|
||||
page = page || 1
|
||||
|
||||
let $ = await Util.get(`${Config.baseUrl}${url}/page/${page}`)
|
||||
let result = {
|
||||
count: $(".content-layout .title-h-left .icon-spot").text().replace(/[^\d]/g, ""),
|
||||
introduce: $(".content-layout .muted-2-color").text(),
|
||||
totalPage: Util.maxPage(".pagenav a", $),
|
||||
currentPage: page,
|
||||
list: []
|
||||
}
|
||||
|
||||
$(".content-layout .posts-row .posts-item").each(function (i) {
|
||||
result.list.push({
|
||||
id: Util.split($(this).find(".item-thumbnail a").attr("href")).replace(/[^\d]/g, ""),
|
||||
thumbnail: $(this).find(".item-thumbnail a img").attr("data-src"),
|
||||
title: $(this).find(".item-body .item-heading a").text(),
|
||||
time: $(this).find(".item-body .item-meta .icon-circle").text(),
|
||||
view: $(this).find(".item-body .item-meta .meta-right .meta-view").text()
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
res.json({
|
||||
status: 200,
|
||||
copyright: `bmy ${new Date()}`,
|
||||
data: result
|
||||
});
|
||||
})
|
||||
|
||||
export default router
|
||||
81
项目合集/最新写真app/backend/utils/index.js
Normal file
81
项目合集/最新写真app/backend/utils/index.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import * as cheer from "cheerio";
|
||||
import axios from "axios";
|
||||
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||
import Config from "../config/config.js";
|
||||
|
||||
class utils {
|
||||
constructor() {
|
||||
this.ax = axios
|
||||
// 让 ajax 请求 走flclash的翻墙代理
|
||||
const httpsAgent = new HttpsProxyAgent(`http://127.0.0.1:${Config.proxyPort}`);
|
||||
this.ax.defaults.httpsAgent = httpsAgent;
|
||||
this.ax.defaults.proxy = false;
|
||||
|
||||
this.ResponseInterceptor()
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 cheerio 数据结构
|
||||
* @param html
|
||||
* @returns {*}
|
||||
*/
|
||||
cheerio(html) {
|
||||
return cheer.load(html)
|
||||
}
|
||||
|
||||
split(str, index = 1) {
|
||||
return str.split(Config.baseUrl)[index]
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param url 请求的地址
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
async get(url) {
|
||||
return await this.ax.get(url, {
|
||||
headers: {
|
||||
'sec-ch-ua-mobile': '?1',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'upgrade-insecure-requests': '1',
|
||||
'priority': 'u=0, i',
|
||||
'sec-fetch-mode': 'navigate',
|
||||
'cookie': `_ga=GA1.1.1571194344.1732275775; _lscache_vary=0e8aace2958628a1edb01710bbabbcab; showed_system_notice=showed; PHPSESSID=5jmev023fsh6i76huat60njio3; _ga_ZT9Q6FCC5R=GS1.1.1732668048.9.1.1732668791.0.0.0`,
|
||||
'referer': 'https://www.06se.com/hot_tags',
|
||||
'user-agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
maxPage(el, $) {
|
||||
let pageArr = []
|
||||
$(el).each(function() {
|
||||
let page = Number($(this).text())
|
||||
page ? pageArr.push(page) : null
|
||||
})
|
||||
return Math.max(...pageArr)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 响应拦截器
|
||||
* @constructor
|
||||
*/
|
||||
async ResponseInterceptor() {
|
||||
this.ax.interceptors.response.use((response) => {
|
||||
return this.cheerio(response.data);
|
||||
}, (error) => {
|
||||
console.log(`
|
||||
❌ 请求错误❕❕❕
|
||||
1: 错误信息 ${error.message}
|
||||
2: 原因:目标网站禁止国内大陆IP访问,爬虫会走系统代理进行请求访问
|
||||
但检测到你未开启翻墙工具,请打开Clash或FlClash等代理工具,保证能正常访问 Google。
|
||||
|
||||
3: 自定义代理端口:修改代码'/config/config.js'中 proxyPort 实现自定义端口,端口从代理工具中查看
|
||||
`);
|
||||
return Promise.reject(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new utils();
|
||||
12
项目合集/最新写真app/backend/utils/ip.js
Normal file
12
项目合集/最新写真app/backend/utils/ip.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import ip from 'ip'
|
||||
|
||||
class IP {
|
||||
ipv6() {
|
||||
return ip.address('private','ipv6')
|
||||
}
|
||||
ipv4() {
|
||||
return ip.address('public','ipv4')
|
||||
}
|
||||
}
|
||||
|
||||
export const {ipv6,ipv4} = new IP()
|
||||
Reference in New Issue
Block a user