C# 写个小爬虫,实现爬取js加载后的网页

一、前言

因工作需求,需要爬取一网页的表格数据,还要用C#来写,自己搜搜看看捣鼓出了这篇教程。

二、思路

一开始用 WebClient 类 什么的去爬,发现爬的是未加载js的html,没有表格数据我想这就应该要获取加载js渲染后的网页源码,看了下请求,有个html,两个json其中一个json就是目标数据,可惜我比较菜,请求url没有拼出来,用payload参数请求失败了,遂放弃了,就把目标转到js渲染后的源代码

三、库安装

开整,C#嘛!那肯定是Visual Studio!!!
首先新建个项目,控制台程序还是窗口程序就你喜欢了,我用控制台应用程序

然后给项目要安装需要的库
Selenium.WebDriver.ChromeDriver
Selenium.PhantomJS.WebDriver
Selenium.WebDriver ps:低版本的才有OpenQA.Selenium.PhantomJS,我装的是 3.0.0

安装完 ,生成一下

四、码代码

using System;
//添加selenium的引用
using OpenQA.Selenium.PhantomJS;
using OpenQA.Selenium.Chrome;
//using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Data;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static ChromeDriver driver { get; set; }
        static ICookieJar cookie { get; set; }
        static void Main(string[] args)
        {
            var url = @"https://s8hwxkltn6.jiandaoyun.com/dash/5f48d400a25baa0006034c29"; 
            GetHtml(url);
        }

        private static void GetHtml(string url)
        {
            PhantomJSDriverService driverService = PhantomJSDriverService.CreateDefaultService();
            driverService.IgnoreSslErrors = true;
            ChromeOptions options = new ChromeOptions();
            options.AddArgument("--headless");
            options.AddArgument("--nogpu");
            List<String> tagNmaeList = new List<string>();
            using (driver = new ChromeDriver(options))
            {
                try
                {
                    driver.Manage().Window.Maximize();
                    driver.Navigate().GoToUrl(url);
                    Thread.Sleep(5000);
                    Console.WriteLine(driver.PageSource); //输出网页源码
                }
                catch (NoSuchElementException)
                {
                    Console.WriteLine("找不到该元素"); ;
                }
            }

        }

五、解析数据

添加方法

//分析HTML 数据
private static void GetData(string ddd)
{

    DataRow dr;
    DataTable dt = new DataTable();  //创建datatable,存储数据
    dt.Columns.Add(new System.Data.DataColumn("序号", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("要求到货时间", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("合同号", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("地址", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("货物名称", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("规格型号", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("公司型号", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("单位", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("数量", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("理论重量", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("金额", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("备注", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("合同号2", typeof(System.String)));

    string oo = string.Empty;
    string kk = string.Empty;
    string ll = string.Empty;
    string hh = string.Empty;
    string fileConent = string.Empty;
    string tableContent = string.Empty;
    string rowContent = string.Empty;
    string columnConent = string.Empty;

    string rowPatterm = @"<tr[^>]*>[\s\S]*?<\/tr>";  // 正则取tr行
    string columnPattern = @"<td[^>]*>[\s\S]*?<\/td>"; // 正则取每行的单元格
    
    MatchCollection rowCollection = Regex.Matches(ddd, rowPatterm, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); //对tr进行筛选
    for (int i = 1; i < rowCollection.Count; i++)
    {
        rowContent = rowCollection[i].Value;
        MatchCollection columnCollection = Regex.Matches(rowContent, columnPattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); //对td进行筛选
        if (i == 1) continue; // 第一行表头来的,直接不要,你也可以用来生成datable的列

        #region 数据筛选
        dr = dt.NewRow(); // 创建新行
        for (int j = 0; j < columnCollection.Count - 1; j++)
        {
            columnConent = columnCollection[j].Value;
            int iBodyStart = columnConent.IndexOf(">", 0);
            int iTableEnd = columnConent.IndexOf("</td>", iBodyStart);
            string strWeb = (columnConent.Substring(iBodyStart + 1, iTableEnd - iBodyStart - 1)).Replace("<span>", "").Replace("</span>", ""); //获取最终数据

            if (columnCollection.Count == 14)
            {
                if (j == 0) dr[0] = oo = strWeb;
                if (j == 1) dr[1] = kk = strWeb;
                if (j == 2) dr[2] = ll = strWeb;
                if (j == 3) dr[3] = hh = strWeb;
                if (j > 3) dr[j] = strWeb;
            }
            else
            {
                if (j == 0) dr[j] = oo;
                if (j == 1) dr[j] = kk;
                if (j == 2) dr[j] = ll;
                if (j == 3) dr[j] = hh;
                dr[j + 4] = strWeb;
            }

        }
        dt.Rows.Add(dr);
        #endregion
    }
}

六、翻页

在GetHtml() 方法内修改一下部分,其中

using (driver = new ChromeDriver(options))
{
    try
    {
        driver.Manage().Window.Maximize();
        driver.Navigate().GoToUrl(url);
        Thread.Sleep(5000);
        // 点击按钮
        driver.ExecuteScript("return $('.count-sel').click()");
        Thread.Sleep(500);
        // 选择一百条每页
        driver.ExecuteScript("return $(\".x-dropdown a[option='100']\").click()");
   		Thread.Sleep(1000);  // 给点时间加载网页
        //Console.WriteLine(driver.PageSource); //输出网页源码
        //GetCookie();
        GetData(driver.PageSource);  // 调用解析数据方法,得到数据datatable 
    }
    catch (NoSuchElementException)
    {
        Console.WriteLine("找不到该元素"); ;
    }
}

七、登录问题

以下方法旨在演示如何登录,说白了就是用js代码模拟输入点击登录的方式实现代码自动登录网站,仅供参考

private static void Login(ChromeDriver driver)
{
    // driver.FindElement(By.Id("btn_Login")).GetAttribute("value");
    //2.执行 js 获取 value 的值
    //driver.ExecuteScript("return document.getElementsById('txt_AccountId')[0].value;");
    driver.ExecuteScript("return $('#帐号输入框ID').val('账号')"); //账号密码
    driver.ExecuteScript("return $('#密码输入框ID').val('密码')");
	// 3.执行jQuery 获取 value 的值
    var account = driver.ExecuteScript("return $('#帐号输入框ID').val()");
    var pass = driver.ExecuteScript("return $('#密码输入框ID').val()");

    driver.FindElement(By.Id("登录按钮ID")).Click(); //点击登录
    Thread.Sleep(1000);  // 给点时间加载网页
}

八、cookie问题

以下方法旨在演示如何获取Cookie,仅供参考

private static void GetCookie()
{
    cookie = driver.Manage().Cookies;  //主要方法

    //显示初始Cookie的内容
    Console.WriteLine("--------------------");
    Console.WriteLine($"当前Cookie集合的数量:\t{cookie.AllCookies.Count}");
    for (int i = 0; i < cookie.AllCookies.Count; i++)
    {
        Console.WriteLine($"Cookie的名称:{cookie.AllCookies[i].Name}");
        Console.WriteLine($"Cookie的值:{cookie.AllCookies[i].Value}");
        Console.WriteLine($"Cookie的所在域:{cookie.AllCookies[i].Domain}");
        Console.WriteLine($"Cookie的路径:{cookie.AllCookies[i].Path}");
        Console.WriteLine($"Cookie的过期时间:{cookie.AllCookies[i].Expiry}");
        Console.WriteLine("--------------------");
    }
}

九、结束

driver 相当于一个网页页面,无论是加载网址还是js异步操作,都相当于在图形页面的点击加载操作,所以需要给予一点时间加载网页,driver 是一直在变的,这就是模拟浏览器进行爬取页面的方法。理论上可以直接给driver执行js代码,而Selenium 有提供部分的方法,有兴趣可以看看。

觉得不错的话可以关注本人的微信公众号:啡小乐,里面会有很多不错的资料分享。

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值