淘寶地址爬取及UI展示
淘寶國家省市區街道獲取
參考 foxiswho 的 taobao-area-php 部分代碼,改由c#重構。
引用如下:
- Autofac
- MediatR
- Swagger
- HangFire 生成街道數據爬取任務。
演示
https://akinix.github.io/Taobao-Area-CSharp/index.html
前端源碼稍后上傳,請關注 deepfunc
Release
生成的release中包含省市區縣.js和街道.json.
目的
為了方便獲取中國大陸及港澳台省市區縣街道相關數據,根據 淘寶地址js,解析並生成相關數據。
設置
所有設置都在 appsettings.json
中
說明 | 默認值 | |
---|---|---|
TaobaoJsVersion | 淘寶js的版本,方便淘寶js更新后修改 | 6.0.14 |
TaobaoAreaJsUrl | 默認值中有占位符,會替換為TaobaoJsVersion的值 | https://g.alicdn.com/vip/address/{0}/index-min.js |
JsDirectoryName | 生成的相關js及json文件的目錄 | js |
JsTemplate | 生成的js模版 | 見代碼 |
AreaPickerDataJsName | 生成的js文件名,默認值中有占位符,會替換為TaobaoJsVersion的值 | area.picker.data.{0}.js |
TaobaoStreetUrl | 爬取街道使用的url | https://lsp.wuliu.taobao.com/locationservice/addr/output_address_town_array.do?l1={0}&l2={1}&l3={2} |
TempDirectoryName | 臨時目錄,下載淘寶js用 | temp |
使用
-
克隆或下載代碼,打開解決方案。
-
F5
或Ctrl+F5
調試代碼。 -
訪問http://localhost:55516/ ,默認會進入Swagger頁面。
-
再打開一個新頁面,訪問Hangfire面板 http://localhost:55516/hangfire/jobs/enqueued, 可以查看爬取街道的任務執行情況.
-
如需演示整個流程,請在Swagger頁面,執行
/api/v1/TaobaoAreas/ReBuild
,該邏輯會重新下載js及重新爬取街道信息;執行/api/v1/TaobaoAreas/Build
則會根據js是否存在來下載,根據json是否存在來爬取數據.
設計說明
概述
核心邏輯說明:
詳細
-
項目基於Asp.net Core,使用了幾個核心包:
Autofac.Extensions.DependencyInjection:替換core的默認Ioc容器.
MediatR:用於業務邏輯解耦.
Swashbuckle.AspNetCore:生成Api的文檔,供測試.
HangFire:后台任務,處理爬取街道邏輯.
Hangfire.MemoryStorage:只使用內存存儲Hangfire任務
-
配置
TaobaoAreaSettings.cs
代碼如下:
public class TaobaoAreaSettings
{
public string TempDirectoryName { get; set; }
public string TaobaoJsVersion { get; set; }
public string TaobaoAreaJsUrl { get; set; }
public string JsTemplate { get; set; }
public string AreaPickerDataJsName { get; set; }
public string TaobaoStreetUrl { get; set; }
public string JsDirectoryName { get; set; }
}
詳細說明參見上面 設置
- 上下文
AreaContextService
,代碼片段如下,詳情請查看github源碼,該類注入為InstancePerLifetimeScope
,每次請求會創建一個新對象,注入相關代碼查看AutofacModules\ApplicationModule.cs
builder.Register(c => new AreaContextService())
.As<AreaContextService>()
.InstancePerLifetimeScope();
其內部主要維護整個邏輯執行過程中需要的數據
public bool IsForce { get; private set; } // 是否強制重新生成js及重新爬取街道數據
public Dictionary<string, object> MainDictionary { get; set; } // 主數據字典:最終生成js時需要的數據
public string ProvinceString { get; private set; }
public string GangAoString { get; private set; }
//... 拆分所需字段
- MediatR相關服務注入:
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
.AsImplementedInterfaces();
// 注入IRequestHandler和INotificationHandler的相關實現
// Send -> RequestHandler
// Publish -> NotificationHandler
var mediatrOpenTypes = new[]
{
typeof(IRequestHandler<,>),
typeof(IRequestHandler<>),
typeof(INotificationHandler<>),
};
foreach (var mediatrOpenType in mediatrOpenTypes)
{
builder
.RegisterAssemblyTypes(typeof(MediatorModule).GetTypeInfo().Assembly)
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
// 參照官網
builder.Register<SingleInstanceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
});
builder.Register<MultiInstanceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t =>
{
var resolved = (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
return resolved;
};
});
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));