第一个爬虫,但是感觉是不能用的。

This commit is contained in:
cheney 2026-04-17 20:37:44 +08:00
parent c61610db20
commit 2820adfdd3
14 changed files with 2846 additions and 1174 deletions

View File

@ -38,7 +38,12 @@ export type Strategy = Prisma.StrategyModel
*/ */
export type Indicator = Prisma.IndicatorModel export type Indicator = Prisma.IndicatorModel
/** /**
* Model SowInventory * Model Econ_SowInventory
* *
*/ */
export type SowInventory = Prisma.SowInventoryModel export type Econ_SowInventory = Prisma.Econ_SowInventoryModel
/**
* Model ScraperCache
*
*/
export type ScraperCache = Prisma.ScraperCacheModel

View File

@ -62,7 +62,12 @@ export type Strategy = Prisma.StrategyModel
*/ */
export type Indicator = Prisma.IndicatorModel export type Indicator = Prisma.IndicatorModel
/** /**
* Model SowInventory * Model Econ_SowInventory
* *
*/ */
export type SowInventory = Prisma.SowInventoryModel export type Econ_SowInventory = Prisma.Econ_SowInventoryModel
/**
* Model ScraperCache
*
*/
export type ScraperCache = Prisma.ScraperCacheModel

View File

@ -150,6 +150,95 @@ export type JsonWithAggregatesFilterBase<$PrismaModel = never> = {
_max?: Prisma.NestedJsonFilter<$PrismaModel> _max?: Prisma.NestedJsonFilter<$PrismaModel>
} }
export type StringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null
notIn?: string[] | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
search?: string
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type JsonNullableFilter<$PrismaModel = never> =
| Prisma.PatchUndefined<
Prisma.Either<Required<JsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>,
Required<JsonNullableFilterBase<$PrismaModel>>
>
| Prisma.OptionalFlat<Omit<Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>
export type JsonNullableFilterBase<$PrismaModel = never> = {
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
path?: string
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
lt?: runtime.InputJsonValue
lte?: runtime.InputJsonValue
gt?: runtime.InputJsonValue
gte?: runtime.InputJsonValue
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
}
export type SortOrderInput = {
sort: Prisma.SortOrder
nulls?: Prisma.NullsOrder
}
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null
notIn?: string[] | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
search?: string
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
| Prisma.PatchUndefined<
Prisma.Either<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>
>
| Prisma.OptionalFlat<Omit<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>
export type JsonNullableWithAggregatesFilterBase<$PrismaModel = never> = {
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
path?: string
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
lt?: runtime.InputJsonValue
lte?: runtime.InputJsonValue
gt?: runtime.InputJsonValue
gte?: runtime.InputJsonValue
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedJsonNullableFilter<$PrismaModel>
_max?: Prisma.NestedJsonNullableFilter<$PrismaModel>
}
export type NestedIntFilter<$PrismaModel = never> = { export type NestedIntFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
in?: number[] in?: number[]
@ -270,4 +359,72 @@ export type NestedJsonFilterBase<$PrismaModel = never> = {
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
} }
export type NestedStringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null
notIn?: string[] | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
search?: string
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null
notIn?: string[] | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
search?: string
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type NestedIntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | null
notIn?: number[] | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type NestedJsonNullableFilter<$PrismaModel = never> =
| Prisma.PatchUndefined<
Prisma.Either<Required<NestedJsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>,
Required<NestedJsonNullableFilterBase<$PrismaModel>>
>
| Prisma.OptionalFlat<Omit<Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>
export type NestedJsonNullableFilterBase<$PrismaModel = never> = {
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
path?: string
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
lt?: runtime.InputJsonValue
lte?: runtime.InputJsonValue
gt?: runtime.InputJsonValue
gte?: runtime.InputJsonValue
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
}

File diff suppressed because one or more lines are too long

View File

@ -388,7 +388,8 @@ export const ModelName = {
Article: 'Article', Article: 'Article',
Strategy: 'Strategy', Strategy: 'Strategy',
Indicator: 'Indicator', Indicator: 'Indicator',
SowInventory: 'SowInventory' Econ_SowInventory: 'Econ_SowInventory',
ScraperCache: 'ScraperCache'
} as const } as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName] export type ModelName = (typeof ModelName)[keyof typeof ModelName]
@ -404,7 +405,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions omit: GlobalOmitOptions
} }
meta: { meta: {
modelProps: "user" | "article" | "strategy" | "indicator" | "sowInventory" modelProps: "user" | "article" | "strategy" | "indicator" | "econ_SowInventory" | "scraperCache"
txIsolationLevel: TransactionIsolationLevel txIsolationLevel: TransactionIsolationLevel
} }
model: { model: {
@ -672,69 +673,135 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
} }
} }
} }
SowInventory: { Econ_SowInventory: {
payload: Prisma.$SowInventoryPayload<ExtArgs> payload: Prisma.$Econ_SowInventoryPayload<ExtArgs>
fields: Prisma.SowInventoryFieldRefs fields: Prisma.Econ_SowInventoryFieldRefs
operations: { operations: {
findUnique: { findUnique: {
args: Prisma.SowInventoryFindUniqueArgs<ExtArgs> args: Prisma.Econ_SowInventoryFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> | null result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload> | null
} }
findUniqueOrThrow: { findUniqueOrThrow: {
args: Prisma.SowInventoryFindUniqueOrThrowArgs<ExtArgs> args: Prisma.Econ_SowInventoryFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
findFirst: { findFirst: {
args: Prisma.SowInventoryFindFirstArgs<ExtArgs> args: Prisma.Econ_SowInventoryFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> | null result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload> | null
} }
findFirstOrThrow: { findFirstOrThrow: {
args: Prisma.SowInventoryFindFirstOrThrowArgs<ExtArgs> args: Prisma.Econ_SowInventoryFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
findMany: { findMany: {
args: Prisma.SowInventoryFindManyArgs<ExtArgs> args: Prisma.Econ_SowInventoryFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload>[] result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>[]
} }
create: { create: {
args: Prisma.SowInventoryCreateArgs<ExtArgs> args: Prisma.Econ_SowInventoryCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
createMany: { createMany: {
args: Prisma.SowInventoryCreateManyArgs<ExtArgs> args: Prisma.Econ_SowInventoryCreateManyArgs<ExtArgs>
result: BatchPayload result: BatchPayload
} }
delete: { delete: {
args: Prisma.SowInventoryDeleteArgs<ExtArgs> args: Prisma.Econ_SowInventoryDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
update: { update: {
args: Prisma.SowInventoryUpdateArgs<ExtArgs> args: Prisma.Econ_SowInventoryUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
deleteMany: { deleteMany: {
args: Prisma.SowInventoryDeleteManyArgs<ExtArgs> args: Prisma.Econ_SowInventoryDeleteManyArgs<ExtArgs>
result: BatchPayload result: BatchPayload
} }
updateMany: { updateMany: {
args: Prisma.SowInventoryUpdateManyArgs<ExtArgs> args: Prisma.Econ_SowInventoryUpdateManyArgs<ExtArgs>
result: BatchPayload result: BatchPayload
} }
upsert: { upsert: {
args: Prisma.SowInventoryUpsertArgs<ExtArgs> args: Prisma.Econ_SowInventoryUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$SowInventoryPayload> result: runtime.Types.Utils.PayloadToResult<Prisma.$Econ_SowInventoryPayload>
} }
aggregate: { aggregate: {
args: Prisma.SowInventoryAggregateArgs<ExtArgs> args: Prisma.Econ_SowInventoryAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateSowInventory> result: runtime.Types.Utils.Optional<Prisma.AggregateEcon_SowInventory>
} }
groupBy: { groupBy: {
args: Prisma.SowInventoryGroupByArgs<ExtArgs> args: Prisma.Econ_SowInventoryGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.SowInventoryGroupByOutputType>[] result: runtime.Types.Utils.Optional<Prisma.Econ_SowInventoryGroupByOutputType>[]
} }
count: { count: {
args: Prisma.SowInventoryCountArgs<ExtArgs> args: Prisma.Econ_SowInventoryCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.SowInventoryCountAggregateOutputType> | number result: runtime.Types.Utils.Optional<Prisma.Econ_SowInventoryCountAggregateOutputType> | number
}
}
}
ScraperCache: {
payload: Prisma.$ScraperCachePayload<ExtArgs>
fields: Prisma.ScraperCacheFieldRefs
operations: {
findUnique: {
args: Prisma.ScraperCacheFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload> | null
}
findUniqueOrThrow: {
args: Prisma.ScraperCacheFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
findFirst: {
args: Prisma.ScraperCacheFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload> | null
}
findFirstOrThrow: {
args: Prisma.ScraperCacheFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
findMany: {
args: Prisma.ScraperCacheFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>[]
}
create: {
args: Prisma.ScraperCacheCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
createMany: {
args: Prisma.ScraperCacheCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.ScraperCacheDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
update: {
args: Prisma.ScraperCacheUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
deleteMany: {
args: Prisma.ScraperCacheDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.ScraperCacheUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.ScraperCacheUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ScraperCachePayload>
}
aggregate: {
args: Prisma.ScraperCacheAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateScraperCache>
}
groupBy: {
args: Prisma.ScraperCacheGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.ScraperCacheGroupByOutputType>[]
}
count: {
args: Prisma.ScraperCacheCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.ScraperCacheCountAggregateOutputType> | number
} }
} }
} }
@ -826,7 +893,7 @@ export const IndicatorScalarFieldEnum = {
export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum] export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum]
export const SowInventoryScalarFieldEnum = { export const Econ_SowInventoryScalarFieldEnum = {
id: 'id', id: 'id',
month: 'month', month: 'month',
inventory: 'inventory', inventory: 'inventory',
@ -834,7 +901,20 @@ export const SowInventoryScalarFieldEnum = {
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const
export type SowInventoryScalarFieldEnum = (typeof SowInventoryScalarFieldEnum)[keyof typeof SowInventoryScalarFieldEnum] export type Econ_SowInventoryScalarFieldEnum = (typeof Econ_SowInventoryScalarFieldEnum)[keyof typeof Econ_SowInventoryScalarFieldEnum]
export const ScraperCacheScalarFieldEnum = {
id: 'id',
scraperName: 'scraperName',
lastDataHash: 'lastDataHash',
lastUpdateAt: 'lastUpdateAt',
metadata: 'metadata',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type ScraperCacheScalarFieldEnum = (typeof ScraperCacheScalarFieldEnum)[keyof typeof ScraperCacheScalarFieldEnum]
export const SortOrder = { export const SortOrder = {
@ -852,6 +932,14 @@ export const JsonNullValueInput = {
export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput] export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput]
export const NullableJsonNullValueInput = {
DbNull: DbNull,
JsonNull: JsonNull
} as const
export type NullableJsonNullValueInput = (typeof NullableJsonNullValueInput)[keyof typeof NullableJsonNullValueInput]
export const UserOrderByRelevanceFieldEnum = { export const UserOrderByRelevanceFieldEnum = {
name: 'name', name: 'name',
email: 'email', email: 'email',
@ -904,11 +992,27 @@ export const IndicatorOrderByRelevanceFieldEnum = {
export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum] export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum]
export const SowInventoryOrderByRelevanceFieldEnum = { export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
month: 'month' month: 'month'
} as const } as const
export type SowInventoryOrderByRelevanceFieldEnum = (typeof SowInventoryOrderByRelevanceFieldEnum)[keyof typeof SowInventoryOrderByRelevanceFieldEnum] export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
export const ScraperCacheOrderByRelevanceFieldEnum = {
scraperName: 'scraperName',
lastDataHash: 'lastDataHash'
} as const
export type ScraperCacheOrderByRelevanceFieldEnum = (typeof ScraperCacheOrderByRelevanceFieldEnum)[keyof typeof ScraperCacheOrderByRelevanceFieldEnum]
@ -1057,7 +1161,8 @@ export type GlobalOmitConfig = {
article?: Prisma.ArticleOmit article?: Prisma.ArticleOmit
strategy?: Prisma.StrategyOmit strategy?: Prisma.StrategyOmit
indicator?: Prisma.IndicatorOmit indicator?: Prisma.IndicatorOmit
sowInventory?: Prisma.SowInventoryOmit econ_SowInventory?: Prisma.Econ_SowInventoryOmit
scraperCache?: Prisma.ScraperCacheOmit
} }
/* Types for Logging */ /* Types for Logging */

View File

@ -55,7 +55,8 @@ export const ModelName = {
Article: 'Article', Article: 'Article',
Strategy: 'Strategy', Strategy: 'Strategy',
Indicator: 'Indicator', Indicator: 'Indicator',
SowInventory: 'SowInventory' Econ_SowInventory: 'Econ_SowInventory',
ScraperCache: 'ScraperCache'
} as const } as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName] export type ModelName = (typeof ModelName)[keyof typeof ModelName]
@ -123,7 +124,7 @@ export const IndicatorScalarFieldEnum = {
export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum] export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum]
export const SowInventoryScalarFieldEnum = { export const Econ_SowInventoryScalarFieldEnum = {
id: 'id', id: 'id',
month: 'month', month: 'month',
inventory: 'inventory', inventory: 'inventory',
@ -131,7 +132,20 @@ export const SowInventoryScalarFieldEnum = {
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const
export type SowInventoryScalarFieldEnum = (typeof SowInventoryScalarFieldEnum)[keyof typeof SowInventoryScalarFieldEnum] export type Econ_SowInventoryScalarFieldEnum = (typeof Econ_SowInventoryScalarFieldEnum)[keyof typeof Econ_SowInventoryScalarFieldEnum]
export const ScraperCacheScalarFieldEnum = {
id: 'id',
scraperName: 'scraperName',
lastDataHash: 'lastDataHash',
lastUpdateAt: 'lastUpdateAt',
metadata: 'metadata',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type ScraperCacheScalarFieldEnum = (typeof ScraperCacheScalarFieldEnum)[keyof typeof ScraperCacheScalarFieldEnum]
export const SortOrder = { export const SortOrder = {
@ -149,6 +163,14 @@ export const JsonNullValueInput = {
export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput] export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput]
export const NullableJsonNullValueInput = {
DbNull: DbNull,
JsonNull: JsonNull
} as const
export type NullableJsonNullValueInput = (typeof NullableJsonNullValueInput)[keyof typeof NullableJsonNullValueInput]
export const UserOrderByRelevanceFieldEnum = { export const UserOrderByRelevanceFieldEnum = {
name: 'name', name: 'name',
email: 'email', email: 'email',
@ -201,9 +223,25 @@ export const IndicatorOrderByRelevanceFieldEnum = {
export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum] export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum]
export const SowInventoryOrderByRelevanceFieldEnum = { export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
month: 'month' month: 'month'
} as const } as const
export type SowInventoryOrderByRelevanceFieldEnum = (typeof SowInventoryOrderByRelevanceFieldEnum)[keyof typeof SowInventoryOrderByRelevanceFieldEnum] export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
export const ScraperCacheOrderByRelevanceFieldEnum = {
scraperName: 'scraperName',
lastDataHash: 'lastDataHash'
} as const
export type ScraperCacheOrderByRelevanceFieldEnum = (typeof ScraperCacheOrderByRelevanceFieldEnum)[keyof typeof ScraperCacheOrderByRelevanceFieldEnum]

View File

@ -12,5 +12,6 @@ export type * from './models/User.ts'
export type * from './models/Article.ts' export type * from './models/Article.ts'
export type * from './models/Strategy.ts' export type * from './models/Strategy.ts'
export type * from './models/Indicator.ts' export type * from './models/Indicator.ts'
export type * from './models/SowInventory.ts' export type * from './models/Econ_SowInventory.ts'
export type * from './models/ScraperCache.ts'
export type * from './commonInputTypes.ts' export type * from './commonInputTypes.ts'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
-- CreateTable
CREATE TABLE `ScraperCache` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`scraperName` VARCHAR(191) NOT NULL,
`lastDataHash` VARCHAR(191) NULL,
`lastUpdateAt` DATETIME(3) NOT NULL,
`metadata` JSON NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `ScraperCache_scraperName_key`(`scraperName`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

View File

@ -56,3 +56,13 @@ model Econ_SowInventory {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
} }
model ScraperCache {
id Int @id @default(autoincrement())
scraperName String @unique // 爬虫名称sow-inventory
lastDataHash String? // 上次数据指纹
lastUpdateAt DateTime // 上次更新时间
metadata Json? // 其他元数据
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

3
scripts/scraper/code.md Normal file
View File

@ -0,0 +1,3 @@
git:<http://git.honor3.com/Fullstack/iboard>
dragon:D:\workbench\iboard

View File

@ -1,7 +1,5 @@
const axios = require('axios'); const axios = require('axios');
const cheerio = require('cheerio'); const cheerio = require('cheerio');
const fs = require('fs');
const path = require('path');
const { PrismaClient } = require('../../generated/prisma'); const { PrismaClient } = require('../../generated/prisma');
const prisma = new PrismaClient(); const prisma = new PrismaClient();
@ -9,12 +7,123 @@ const prisma = new PrismaClient();
// 浙江数据开放网站URL示例实际需要根据真实网站修改 // 浙江数据开放网站URL示例实际需要根据真实网站修改
const ZHEJIANG_OPEN_DATA_URL = 'https://data.zj.gov.cn/'; const ZHEJIANG_OPEN_DATA_URL = 'https://data.zj.gov.cn/';
// 能繁母猪数量数据爬取函数 // 爬虫名称,用于缓存表中的标识
async function scrapeSowInventory() { const SCRAPER_NAME = 'sow-inventory';
// 最小更新间隔毫秒默认30分钟
const MIN_UPDATE_INTERVAL = 30 * 60 * 1000;
// 从数据库读取缓存
async function readCache() {
try { try {
const cache = await prisma.scraperCache.findUnique({
where: { scraperName: SCRAPER_NAME }
});
return cache || { scraperName: SCRAPER_NAME, lastDataHash: null, lastUpdateAt: null };
} catch (error) {
console.error('读取数据库缓存失败:', error.message);
return { scraperName: SCRAPER_NAME, lastDataHash: null, lastUpdateAt: null };
}
}
// 写入数据库缓存
async function writeCache(lastDataHash) {
try {
await prisma.scraperCache.upsert({
where: { scraperName: SCRAPER_NAME },
update: {
lastDataHash,
lastUpdateAt: new Date()
},
create: {
scraperName: SCRAPER_NAME,
lastDataHash,
lastUpdateAt: new Date()
}
});
} catch (error) {
console.error('写入数据库缓存失败:', error.message);
}
}
// 计算数据hash用于检测数据是否变化
function computeDataHash(data) {
const str = JSON.stringify(data);
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash.toString();
}
// 获取数据库中最新的月份
async function getLatestMonth() {
try {
const latest = await prisma.econ_SowInventory.findFirst({
orderBy: {
month: 'desc'
}
});
return latest ? latest.month : null;
} catch (error) {
console.error('查询最新月份失败:', error.message);
return null;
}
}
// 判断月份是否需要更新(只有比数据库中更新的月份才需要处理)
function shouldUpdateMonth(month, latestDbMonth) {
if (!latestDbMonth) return true;
return month > latestDbMonth;
}
// 检查是否需要发起HTTP请求基于更新间隔
function shouldSkipRequest(cache) {
if (!cache.lastUpdateAt) return false;
const now = new Date();
const lastUpdate = new Date(cache.lastUpdateAt);
const interval = now - lastUpdate;
return interval < MIN_UPDATE_INTERVAL;
}
// 能繁母猪数量数据爬取函数(增量更新版本)
async function scrapeSowInventory(incremental = true) {
try {
console.log('='.repeat(50));
console.log('开始爬取浙江省能繁母猪数量数据...'); console.log('开始爬取浙江省能繁母猪数量数据...');
console.log(`增量更新模式: ${incremental ? '开启' : '关闭'}`);
console.log('='.repeat(50));
// 0. 检查是否需要发起请求
if (incremental) {
const cache = await readCache();
if (shouldSkipRequest(cache)) {
const lastUpdate = cache.lastUpdateAt ? new Date(cache.lastUpdateAt) : null;
const hoursDiff = lastUpdate ? ((new Date() - lastUpdate) / (1000 * 60 * 60)).toFixed(2) : '未知';
console.log('\n' + '='.repeat(50));
console.log('跳过请求距离上次更新不足30分钟');
console.log(`上次更新时间: ${cache.lastUpdateAt}`);
console.log(`距离现在: ${hoursDiff} 小时`);
console.log('='.repeat(50));
return;
}
// 获取数据库中最新的月份
const latestDbMonth = await getLatestMonth();
if (latestDbMonth) {
console.log(`数据库中最新月份: ${latestDbMonth}`);
} else {
console.log('数据库为空,将获取所有数据');
}
}
// 1. 发送HTTP请求获取页面内容 // 1. 发送HTTP请求获取页面内容
console.log('\n正在请求数据源...');
const response = await axios.get(ZHEJIANG_OPEN_DATA_URL, { const response = await axios.get(ZHEJIANG_OPEN_DATA_URL, {
headers: { headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
@ -25,8 +134,7 @@ async function scrapeSowInventory() {
const $ = cheerio.load(response.data); const $ = cheerio.load(response.data);
// 3. 提取数据(这里需要根据实际网站结构修改选择器) // 3. 提取数据(这里需要根据实际网站结构修改选择器)
// 示例:假设数据在表格中 const allData = [];
const data = [];
$('table').each((tableIndex, table) => { $('table').each((tableIndex, table) => {
$(table).find('tr').each((rowIndex, row) => { $(table).find('tr').each((rowIndex, row) => {
@ -37,7 +145,7 @@ async function scrapeSowInventory() {
const inventory = parseInt($(cells[1]).text().trim()); const inventory = parseInt($(cells[1]).text().trim());
if (month && !isNaN(inventory)) { if (month && !isNaN(inventory)) {
data.push({ allData.push({
month, month,
inventory inventory
}); });
@ -47,10 +155,58 @@ async function scrapeSowInventory() {
}); });
}); });
console.log(`爬取到 ${data.length} 条数据`); console.log(`页面总数据量: ${allData.length}`);
// 4. 存储数据到数据库 // 4. 读取数据库缓存
for (const item of data) { const cache = await readCache();
// 5. 计算当前数据hash检测数据是否变化
const currentDataHash = computeDataHash(allData);
// 6. 如果是增量更新且数据未变化,跳过更新
if (incremental && cache.lastDataHash === currentDataHash) {
console.log('\n' + '='.repeat(50));
console.log('数据未发生变化,跳过数据库更新!');
console.log(`上次更新时间: ${cache.lastUpdateAt || '未知'}`);
console.log('='.repeat(50));
return;
}
// 7. 如果是增量更新,获取数据库中最新的月份用于过滤
let latestDbMonth = null;
if (incremental) {
latestDbMonth = await getLatestMonth();
}
// 8. 过滤需要更新的数据
let dataToUpdate = allData;
let skippedCount = 0;
if (incremental && latestDbMonth) {
dataToUpdate = allData.filter(item => shouldUpdateMonth(item.month, latestDbMonth));
skippedCount = allData.length - dataToUpdate.length;
console.log(`\n增量更新: 跳过 ${skippedCount} 条已存在的数据`);
console.log(`需要处理: ${dataToUpdate.length} 条新数据`);
}
// 9. 如果没有需要更新的数据
if (dataToUpdate.length === 0) {
console.log('\n没有需要更新的数据');
return;
}
// 10. 按月份排序(从旧到新)
dataToUpdate.sort((a, b) => a.month.localeCompare(b.month));
console.log('\n开始处理数据...');
console.log('-'.repeat(50));
let newCount = 0;
let updateCount = 0;
let errorCount = 0;
// 11. 存储数据到数据库
for (const item of dataToUpdate) {
try { try {
// 检查数据是否已存在 // 检查数据是否已存在
const existing = await prisma.econ_SowInventory.findUnique({ const existing = await prisma.econ_SowInventory.findUnique({
@ -58,38 +214,73 @@ async function scrapeSowInventory() {
}); });
if (existing) { if (existing) {
// 更新现有数据 // 检查数据是否真的需要更新(值变化了才更新)
await prisma.econ_SowInventory.update({ if (existing.inventory !== item.inventory) {
where: { month: item.month }, await prisma.econ_SowInventory.update({
data: { inventory: item.inventory } where: { month: item.month },
}); data: { inventory: item.inventory }
console.log(`更新数据: ${item.month} - ${item.inventory}`); });
updateCount++;
console.log(`更新数据: ${item.month} - ${item.inventory} (原值: ${existing.inventory})`);
} else {
console.log(`数据未变化,跳过: ${item.month}`);
}
} else { } else {
// 创建新数据
await prisma.econ_SowInventory.create({ await prisma.econ_SowInventory.create({
data: item data: item
}); });
newCount++;
console.log(`新增数据: ${item.month} - ${item.inventory}`); console.log(`新增数据: ${item.month} - ${item.inventory}`);
} }
} catch (error) { } catch (error) {
errorCount++;
console.error(`处理数据 ${item.month} 时出错:`, error.message); console.error(`处理数据 ${item.month} 时出错:`, error.message);
} }
} }
// 12. 更新数据库缓存
await writeCache(currentDataHash);
// 13. 输出统计信息
const now = new Date().toISOString();
console.log('\n' + '='.repeat(50));
console.log('数据爬取和存储完成!'); console.log('数据爬取和存储完成!');
console.log('统计信息:');
console.log(` - 新增数据: ${newCount}`);
console.log(` - 更新数据: ${updateCount}`);
console.log(` - 跳过数据: ${skippedCount}`);
console.log(` - 错误数量: ${errorCount}`);
console.log(` - 本次更新时间: ${now}`);
console.log('='.repeat(50));
} catch (error) { } catch (error) {
console.error('爬取数据时出错:', error.message); console.error('爬取数据时出错:', error.message);
throw error;
} finally { } finally {
// 关闭Prisma连接 // 关闭Prisma连接
await prisma.$disconnect(); await prisma.$disconnect();
} }
} }
// 强制全量更新函数
async function scrapeSowInventoryFull() {
console.log('警告: 即将执行全量更新,这将更新所有数据!');
console.log('如果只是想获取新数据,请使用 scrapeSowInventory() 函数。\n');
await scrapeSowInventory(false);
}
// 导出函数 // 导出函数
module.exports = { scrapeSowInventory }; module.exports = {
scrapeSowInventory,
scrapeSowInventoryFull
};
// 如果直接运行此文件 // 如果直接运行此文件
if (require.main === module) { if (require.main === module) {
scrapeSowInventory(); // 默认执行增量更新
// 如果需要强制全量更新,使用: scrapeSowInventoryFull()
scrapeSowInventory().catch(error => {
console.error('执行失败:', error);
process.exit(1);
});
} }