接下去进入代码的模块,首先我们分析一下如何实现代码
我们拥有一张类别表,类别表中记录了 类别名称,编码,地址,该类别所拥有的页数等信息
抽象描述:
- 取出所有的类别
- 循环类别集合
循环类别页数
得到当前类别当前页集合数据
插入数据库
对上述内容我们又几个地方需要注意,我们依次说明
第一点 数量量大
类别大致有4000多个,每个类别页数各不相同(一页60个商品是固定的),这么多的商品数据,如果我们还是采用同步方法依次执行的话,效率势必大打折扣,爬取所需花费的时间也很长。这个时候我们就要考虑多线程执行。
作者的思路是这样的:
不管数据量有多少,固定线程数量20个,即我只开20个线程处理任务。每个线程处理一个类别的工作任务。因为有的类别页数有100个,有的类别页数只有10个,这一块如何继续平均分配,不做考虑,各位可以开动大家的脑筋。
第二点 数据库如何存储
如此多的数据,我们应该如何存储。我们爬取的是相同的商品数据,只是内容不同。所以很自然的我们想到了分表。我们既然分表了,那么势必涉及到以后的查询,查询我们以后使用的是Lucene,自己建立一个简答的搜索引擎。在此基础之上,我们在表设计的时候就没有太大的约束。以下是我的商品表的设计图
Id 主键自增
SUID 商品唯一码
CategoryId 商品类别
Titile 商品名称
Description 商品描述
Price 价格
Url 地址
ShopName 店铺名称
商品编码来源于每一个li标签的id【如下图】,我们可以看到这是一个数字编码。我假设这个编码是一个自增的数字,那么我就可以使用百分取余的方法确定这个商品应该放在哪个表中。这是什么意思呢。
我们假设自己有20张表,每个表的数据结构都如上述描述的那样,那我们要解决的问题就是数据应该如何存储的问题。
自增数字的取余意思就是。如果当前编号是30001
30001 % 20=1 存放在商品表1中 Commodity_01
40871 % 20=11 存放在商品表11中 Commodity_11
这样做的好处是什么呢,因为商品如果是自增累加的。通过此方法可以平均分配每张表的数据,不会让某张表数据多,而某张表数据少
第三点 数据插入如何操作
我们可以从上文中了解到,在得到当前也数据后,我们要将其集合(60个)插入数据库,选用何种方式可以保证事务基础上又减少数据库链接是要考虑的问题。
以下是我的思路,贴代码讲解
代码为剪贴版,要看全部代码可以去我的github上面下载最新的源码
//取值
List<POCO_Commodity> cateList = CommodityAnalysis.GetData(category.Url, category.Id, i);
//处理
List<CommodityGroupInput> groupList = cateList.GroupBy(u => Convert.ToInt64(u.SUId) % StaticConst.CategorySheetCount).Select(u => new CommodityGroupInput
{
Id = u.Key,
Units = u.OrderBy(p => p.SUId).ToList()
}).ToList();
//入库
_commodityService.InsertGroupBulk(groupList);
第一步取值,参数为 地址,类别码,页码
第二步是对List集合的分组,分组条件为唯一码%20,得到的内容为
[表索引号,对应的集合]
第三步,入库,代码贴图如下
入库数据库操作我通过dapper实现,不知道dapper是什么的,可以自行百度。代码的解释如下,使用dapper数据库链接,开启事务,对形参集合进行SQL语句拼接。