C# HtmlAgilityPack+Selenium爬取需要拉动滚动条的页面内容
现在大多数网站都是随着滚动条的滑动加载页面内容的,因此单纯获得静态页面的Html是无法获得全部的页面内容的。使用Selenium就可以模拟浏览器拉动滑动条来加载所有页面内容。
前情提要
Selenium简介
Selenium是一个WEB自动化测试工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。Selenium也是一款同样使用Apache License 2.0协议发布的开源框架。
C#安装Selenium
本文仅仅是使用Selenium实现拉动滚动条的功能,所以不对Selenium进行过多的介绍。
通过Nuget包管理器搜索"Selenium",分别安装:
- Selenium.WebDriver
- Selenium.Chrome.WebDriver
实例(获取某网站主页所有图片)
普通获取网页Html
ChromeDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl(url);
string title = driver.Title;//页面title
string html = driver.PageSource;//页面Html
不启动Chrome窗口及关闭Chrome控制台获取网页
程序执行时会自动打开Chrome窗口和输出控制台中一些信息,我们不需要这些东西。
//不启动chrome窗口
ChromeOptions options = new ChromeOptions();
options.AddArgument("headless");
//关闭ChromeDriver控制台
ChromeDriverService driverService = ChromeDriverService.CreateDefaultService();
driverService.HideCommandPromptWindow = true;
ChromeDriver driver = new ChromeDriver(driverService, options);
driver.Navigate().GoToUrl(url);
将页面滚动到底部
如果使用scrollTo(0, document.body.scrollHeight)
,直接让将页面滚动到底部会导致页面中间部分读取失败,所以需要分几次滑动并且给页面足够的时间加载
for (int i = 1; i <= 10; i++)
{
string jsCode = "window.scrollTo({top: document.body.scrollHeight / 10 * " + i + ", behavior: \"smooth\"});";
//使用IJavaScriptExecutor接口运行js代码
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript(jsCode);
//暂停滚动
Thread.Sleep(1000);
}
使用HtmlAgilityPack解析读取到的Html
以下内容与上一篇文章基本相同
string title = driver.Title;//页面title
string html = driver.PageSource;//页面Html
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);//解析Html字符串
string imgPath = "//img";//选择img
//获取img标签中的图片
foreach (HtmlNode node in doc.DocumentNode.SelectNodes(imgPath))
{
······
}
完整代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using HtmlAgilityPack;
using System.Text.RegularExpressions;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System.Threading;
namespace WebCrawlerDemo
{
class Program
{
static void Main(string[] args)
{
WebClient wc = new WebClient();
int imgNum = 0;//图片编号
string url = "https://www.bilibili.com";
string html = FinalHtml.GetFinalHtml(url, 10);
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
string imgPath = "//img";//选择img
//HtmlNode nodes = hd.DocumentNode.SelectSingleNode(path);
//获取img标签中的图片
foreach (HtmlNode node in doc.DocumentNode.SelectNodes(imgPath))
{
if (node.Attributes["src"] != null)
{
string imgUrl = node.Attributes["src"].Value.ToString();
if (imgUrl != "" && imgUrl != " ")
{
imgNum++;
//生成文件名,自动获取后缀
string fileName = GetImgName(imgUrl, imgNum);
//Console.WriteLine(fileName);
//Console.WriteLine(imgUrl);
ImgDownloader.DownloadImg(wc, imgUrl, "images/", fileName);
}
}
}
//获取背景图
string bgImgPath = "//*[@style]";//选择具有style属性的节点
foreach (HtmlNode node in doc.DocumentNode.SelectNodes(bgImgPath))
{
if (node.Attributes["style"].Value.Contains("background-image:url"))
{
imgNum++;
string bgImgUrl = node.Attributes["style"].Value;
bgImgUrl = Regex.Match(bgImgUrl, @"(?<=\().+?(?=\))").Value;//读取url()的内容
//Console.WriteLine(bgImgUrl);
//生成文件名,自动获取后缀
string fileName = GetImgName(bgImgUrl, imgNum);
ImgDownloader.DownloadImg(wc, bgImgUrl, "images/bgcImg/", fileName);
}
}
Console.WriteLine("----------END----------");
Console.WriteLine($"一共获得: {imgNum}张图");
Console.ReadKey();
}
}
/// <summary>
/// 图片下载器
/// </summary>
public class ImgDownloader
{
/// <summary>
/// 下载图片
/// </summary>
/// <param name="webClient"></param>
/// <param name="url">图片url</param>
/// <param name="folderPath">文件夹路径</param>
/// <param name="fileName">图片名</param>
public static void DownloadImg(WebClient webClient, string url, string folderPath, string fileName)
{
//如果文件夹不存在,则创建一个
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
//判断路径是否完整,补全不完整的路径
if (url.IndexOf("https:") == -1 && url.IndexOf("http:") == -1)
{
url = "https:" + url;
}
//下载图片
try
{
webClient.DownloadFile(url, folderPath + fileName);
Console.WriteLine(fileName + "下载成功");
}
catch (Exception ex)
{
Console.Write(ex.Message);
Console.WriteLine(url);
}
}
/// <summary>
/// 生成图片名称
/// </summary>
/// <param name="imageUrl">图片地址</param>
/// <param name="imageNum">图片编号</param>
/// <returns></returns>
public static string GetImgName(string imageUrl, int imageNum)
{
string imgExtension;
if (imageUrl.LastIndexOf(".") != -1)
{
imgExtension = imageUrl.Substring(imageUrl.LastIndexOf("."));
}
else
{
imgExtension = ".jpg";
}
return imageNum + imgExtension;
}
}
/// <summary>
/// 获得执行过js的网址
/// </summary>
public class FinalHtml
{
/// <summary>
/// 获得拉动滚动条后的页面
/// </summary>
/// <param name="url">网址</param>
/// <param name="sectionNum">滚动几次</param>
/// <returns>html字符串</returns>
public static string GetFinalHtml(string url, int sectionNum)
{
//不启动chrome窗口
ChromeOptions options = new ChromeOptions();
options.AddArgument("headless");
//关闭ChromeDriver控制台
ChromeDriverService driverService = ChromeDriverService.CreateDefaultService();
driverService.HideCommandPromptWindow = true;
ChromeDriver driver = new ChromeDriver(driverService, options);
driver.Navigate().GoToUrl(url);
string title = driver.Title;
Console.WriteLine($"Title: {title}");
//将页面滚动到底部
Console.Write("页面滚动中,请稍后");
for (int i = 1; i <= sectionNum; i++)
{
string jsCode = "window.scrollTo({top: document.body.scrollHeight / " + sectionNum + " * " + i + ", behavior: \"smooth\"});";
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript(jsCode);
Console.Write(".");
Thread.Sleep(1000);
}
Console.WriteLine();
string html = driver.PageSource;
driver.Quit();
return html;
}
}
}
参考文章
C# HtmlAgilityPack+Selenium爬取需要拉动滚动条的页面内容的更多相关文章
- HtmlUnit爬取Ajax动态生成的页面内容
HtmlUnit说白了就是一个浏览器,这个浏览器是用Java写的无界面的浏览器,正因为其没有界面,因此执行的速度还是可以滴. HtmlUnit提供了一系列的API,这些API可以干的功能比较多,如表单 ...
- selenium模块使用详解、打码平台使用、xpath使用、使用selenium爬取京东商品信息、scrapy框架介绍与安装
今日内容概要 selenium的使用 打码平台使用 xpath使用 爬取京东商品信息 scrapy 介绍和安装 内容详细 1.selenium模块的使用 # 之前咱们学requests,可以发送htt ...
- [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
转载自:http://blog.csdn.net/eastmount/article/details/51231852 一. 文章介绍 源码下载地址:http://download.csdn.net/ ...
- selenium爬取煎蛋网
selenium爬取煎蛋网 直接上代码 from selenium import webdriver from selenium.webdriver.support.ui import WebDriv ...
- 利用selenium爬取京东商品信息存放到mongodb
利用selenium爬取京东商城的商品信息思路: 1.首先进入京东的搜索页面,分析搜索页面信息可以得到路由结构 2.根据页面信息可以看到京东在搜索页面使用了懒加载,所以为了解决这个问题,使用递归.等待 ...
- 利用Selenium爬取淘宝商品信息
一. Selenium和PhantomJS介绍 Selenium是一个用于Web应用程序测试的工具,Selenium直接运行在浏览器中,就像真正的用户在操作一样.由于这个性质,Selenium也是一 ...
- Scrapy 框架 使用 selenium 爬取动态加载内容
使用 selenium 爬取动态加载内容 开启中间件 DOWNLOADER_MIDDLEWARES = { 'wangyiPro.middlewares.WangyiproDownloaderMidd ...
- 使用selenium爬取网站动态数据
处理页面动态加载的爬取 selenium selenium是python的一个第三方库,可以实现让浏览器完成自动化的操作,比如说点击按钮拖动滚轮等 环境搭建: 安装:pip install selen ...
- scrapy框架 + selenium 爬取豆瓣电影top250......
废话不说,直接上代码..... 目录结构 items.py import scrapy class DoubanCrawlerItem(scrapy.Item): # 电影名称 movieName = ...
随机推荐
- 咕泡学院java架构vip课程
1.wps文档地址 https://docs.qq.com/doc/DRVNLUndvTmFSdEhO 2.百度网盘地址 https://pan.baidu.com/s/1uxaTzJZHKrsw_H ...
- 微信小程序 base64格式图片的显示及保存
当我们拿到如下base64格式的图片(如下图)时, base64格式的图片数据: 如何显示 ? 使用image标签,src属性添加data:image/png;base64, (注意:若imgData ...
- [C++] inline内联函数使用方法
C++支持内联函数,目的是为了提高函数的执行效率,类似于C语言中的宏定义 内联函数在调用时将它在程序中的每个调用点展开,不用额外分配栈空间 内联函数的定义在一个源文件中出现一次,但在多个源文件中可以同 ...
- vue+elementui搭建后台管理界面(6登录和菜单权限控制)
不同的权限对应不同的路由(菜单),同时侧边栏也根据权限异步生成,实现登录和鉴权思路如下: 登录:点击登录,服务器验证通过后返回一个 token ,然后存到 cookie,再根据 token 拉取用户权 ...
- 第2课第7节_Java面向对象编程_内部类_P【学习笔记】
摘要:韦东山android视频学习笔记 1.什么是内部类:在类的内部定义一个类,内部类可以访问类的私有属性 class Outer{ ; class Inner{ public void print ...
- class文件格式版本号
major version 52:jdk 8, major version 51:jdk 7, major version 50:jdk 6, major version 49:jdk 5, majo ...
- 压测引起的 nginx报错 502 no live upstreams while connecting to upstream解决
对系统的某个接口进行极限压测,随着并发量上升,nginx开始出现502 no live upstreams while connecting to upstream的报错,维持最大并发量一段时间,发现 ...
- Comparator中返回0导致数据丢失的大坑
今天对一列数据进行排序,因为存储的是Map结构,要实现排序,马上就想到了TreeMap,于是查到API,这样新建TreeMap就能实现添加的时候就自动排序. new TreeMap<>(n ...
- LeetCode 993. Cousins in Binary Tree(判断结点是否为Cousin)
993. Cousins in Binary Tree In a binary tree, the root node is at depth 0, and children of each dept ...
- 一秒解决CentOS下service 功能 不能使用 bash: service: command not found
首先检查自己是否 使用的是root用户 如果是并且还不能用-----执行以下操作 在centos系统中,如果/sbin目录下没有service这个命令,就会出现 bash: service: comm ...