发布:2024/1/17 22:21:38作者:管理员 来源:本站 浏览次数:510
一、前言
因工作需求,需要爬取一网页的表格数据,还要用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 有提供部分的方法,有兴趣可以看看。
© Copyright 2014 - 2025 柏港建站平台 ejk5.com. 渝ICP备16000791号-4