c#爬虫爬取京东的商品信息
前言
在一个小项目中,需要用到京东的所有商品id,因此就用c#写了个简单的爬虫。
在解析html中没有使用正则表达式,而是借助开源项目htmlagilitypack解析html。
下面话不多说了,来一起看看详细的介绍吧
一、下载网页html
首先我们写一个公共方法用来下载网页的html。
在写下载html方法之前,我们需要去查看京东网页请求头的相关信息,在发送请求时需要用到。
public static string downloadhtml(string url, encoding encode) { string html = string.empty; try { httpwebrequest request = webrequest.create(url) as httpwebrequest; request.timeout = 30 * 1000; request.useragent = "mozilla/5.0 (windows nt 10.0; wow64) applewebkit/537.36 (khtml, like gecko) chrome/51.0.2704.106 safari/537.36"; request.contenttype = "text/html; charset=utf-8"; using (httpwebresponse response = request.getresponse() as httpwebresponse) { if (response.statuscode == httpstatuscode.ok) { try { streamreader sr = new streamreader(response.getresponsestream(), encode); html = sr.readtoend();//读取数据 sr.close(); } catch (exception ex) { html = null; } } } } catch (system.net.webexception ex) { html = null; } catch (exception ex) { html = null; } return html; }
如上代码所示,我们使用webrequest来获取网页信息,在发送请求之前,需要先设置和京东页面一样的请求头。
以上设置的信息比较简单,但能够正常发送请求,我们也可以模拟浏览器设置cookie等等信息,
二、解析html
获取所有商品的信息分为两个步骤
(1)根据商品分类页面获取所有商品分类的url
(2)根据商品分类url获取每个商品
1、获取商品分类
try { string html = httphelper.downloadurl(@"http://www.jd.com/allsort.aspx"); htmldocument doc = new htmldocument(); doc.loadhtml(html); string goodclass= @"//*[@class='items']/dl/dd"; htmlnodecollection nonenodelist = doc.documentnode.selectnodes(goodclass); foreach (var node in nonenodelist) { htmldocument docchild = new htmldocument(); docchild.loadhtml(node.outerhtml); string urlpath = "/dd/a"; htmlnodecollection list = docchild.documentnode.selectnodes(urlpath); foreach (var l in list) { htmldocument docchild1 = new htmldocument(); docchild1.loadhtml(l.outerhtml); var sorturl = l.attributes["href"].value; if (!string.isnullorwhitespace(sorturl) && sorturl.contains("cat=")) { insertsort("https:" + sorturl); } } } } catch (exception ex) { console.writeline(ex.message); }
上面的代码中使用到了htmlagilitypack来解析html信息,这是.net的开源项目,开源在nuget包中下载。
(1)下载http://www.jd.com/allsort.aspx的html页,然后加载到htmldocument
(2)选择节点,获取每个大类的节点集合
(3)根据每个大类的节点,获取每个小类的节点信息,然后获取到分类地址
节点中也包含了其它很多信息,可以根据自己的需求去获取对应的信息
2、获取具体商品信息
(1)首先根据商品分类加载分类信息,获取到当前分类每个页面的链接
下载html之后,选择节点,可以将html格式化之后查看每个页面的url地址和拼接规则,然后借助htmlagilitypack
来筛选需要的节点,将每个页面的url分离出来
try { string html = httphelper.downloadurl(@"https://list.jd.com/list.html?cat=1620,11158,11964"); htmldocument productdoc = new htmldocument(); productdoc.loadhtml(html); htmlnode pagenode = productdoc.documentnode.selectsinglenode(@"//*[@id='j_toppage']/span/i"); if (pagenode != null) { int pagenum = convert.toint32(pagenode.innertext); for (int i = 1; i < pagenum + 1; i++) { string pageurl = string.format("{0}&page={1}", category.url, i).replace("&page=1&", string.format("&page={0}&", i)); try { list<productinfo> productinfo = getpageproduct(pageurl); } catch (exception ex) { console.writeline(ex.message); } } } } catch (exception ex) { console.writeline(ex.message); }
(2)根据每个页面的链接,获取当前页面的商品信息
下载每个页面的所有商品信息,需要获取的商品信息在页面中都能找到
首先我们获取到每个商品的节点集合,获取到一个商品的节点信息之后,分析html数据,
找到我们需要的商品的信息所在的位置,然后将需要的信息分离出来。
下面的代码中我获取到的商品的id和title还有价格。
list<productinfo> productinfolist = new list<productinfo>(); try { string html = httphelper.downloadurl(url); htmldocument doc = new htmldocument(); doc.loadhtml(html); htmlnodecollection productnodelist = doc.documentnode.selectnodes("//*[@id='plist']/ul/li"); if (productnodelist == null || productnodelist.count == 0) { return productinfolist; } foreach (var node in productnodelist) { htmldocument docchild = new htmldocument(); docchild.loadhtml(node.outerhtml); productinfo productinfo = new productinfo() { categoryid = category.id }; htmlnode urlnode = docchild.documentnode.selectsinglenode("//*[@class='p-name']/a"); if (urlnode == null) { continue; } string newurl= urlnode.attributes["href"].value; newurl = !newurl.startswith("http:")?"http:" + newurl: newurl; string sid = path.getfilename(newurl).replace(".html", ""); productinfo.productid = long.parse(sid); htmlnode titlenode = docchild.documentnode.selectsinglenode("//*[@class='p-name']/a/em"); if (titlenode == null) { continue; } productinfo.title = titlenode.innertext; htmlnode pricenode = docchild.documentnode.selectsinglenode("//*[@class='p-price']/strong/i"); if (pricenode == null) { continue; } else { } productinfolist.add(productinfo); } //批量获取价格 getgoodsprice(productinfolist); } catch (exception ex) { } return productinfolist;
商品的图片地址和价格信息的获取需要仔细分析html中的数据,然后找到规律,比如价格在每个节点中就不能单独获取。
以下为批量获取价格的代码:
try { stringbuilder sb = new stringbuilder(); sb.appendformat("http://p.3.cn/prices/mgets?callback=jquery1069298&type=1&area=1_72_4137_0&skuids={0}&pdbp=0&pdtk=&pdpin=&pduid=1945966343&_=1469022843655", string.join("%2c", productinfolist.select(c => string.format("j_{0}", c.productid)))); string html = httphelper.downloadurl(sb.tostring()); if (string.isnullorwhitespace(html)) { return productinfolist; } html = html.substring(html.indexof("(") + 1); html = html.substring(0, html.lastindexof(")")); list<commodityprice> pricelist = jsonconvert.deserializeobject<list<commodityprice>>(html); productinfolist.foreach(c => c.price = pricelist.firstordefault(p => p.id.equals(string.format("j_{0}", c.productid))).p); } catch (exception ex) { console.writeline(ex.message); } return productinfolist;
以上就是一个简单的爬取京东商品信息的爬虫,也可以根据自己的需求去解析更多的数据出来。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。