很多网页使用了 ajax 技术,浏览器地址栏的链接并不返回全部的内容,而是在加载文档之后,采用异步的请求获取对应的内容。京东商城的商品价格就是 ajax 获取的。这样做有可能是为了优化速度,也有可能是为了防止抓取,或者两者都有。这种网页单纯用 WebClient 无法得到和浏览器访问相同的内容,需要使用 WebBrowser 控件,这个控件相当于在程序中嵌入了一个 IE 浏览器,可以运行网页的脚本,也就可以得到 ajax 请求的内容了。
我写了一个示例四,演示了 Less.Html 和 WebBrowser 的搭配使用。之所要使用 Less.Html,是因为 WebBrowser 只能得到网页的 HTML DOM,DOM 的方法对于获取指定元素的内容是不太方便的,利用 Less.Html 的 css 选择器,可以快速地获取你想要的内容。
源代码:GitHub
这个示例有两个要点,一个是异步线程去检查 ajax 是否完成加载,之所以要使用异步线程,是因为不能阻塞 WebBrowser 的线程;第二个就是使用 Less.Html 的 css 选择器快速获取内容的部分了。这是可以直接用在实际的项目中的,所以我选择了抓取京东手机价格为例:
//获取页面所有的商品 var sku = q(".gl-item");
foreach (Element i in sku) { //商品名称 string name = q(i).find( ".p-name a em").text(); //商品价格 string price = q(i).find( ".p-price i").text(); }
代码中使用了三次 css 选择器,作用如注释所示。相比 WebBrowser 的 DOM 方法,搭配 Less.Html 可以大幅度地提升开发速度。
我在示例中隐藏了 Form,是通过 Console 去开进程调用 Form,然后把 Form 的输出重定向到 Console 的,在程序的运行过程中感觉不到 WebBrowser 的存在。运行示例需要把 Test 这个控制台项目设为启动项目,运行结果如下: