返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
爬虫

Selenium Scraping in Practice: Capturing Images from a Web Page

Preface This was also for grinding courses. I never thought that even after starting work I'd still be unable to escape the same fate as in college of having to grind through online courses... Main text I'll get straight to the useful stuff: capturing images. Everyone knows what kind of image needs to be captured (yes, I'm talking about you, captcha). Other images don't need capturing—just get the URL and download them. Captchas don't work that way; visiting the same URL again changes the content. I don't know why Selenium can't just pull the image out of a specific img element; it's so user-hostile. Based on the materials I found, there are mainly two approaches. One is to simulate mouse operations, on the captcha

曦远 (DealiAxy)约 15 分钟
目录5 个章节

Preface

This was also for grinding courses. I never thought that even after starting work I'd still be unable to escape the same fate as in college of having to grind through online courses...

Main Text

I'll get straight to the useful stuff: capturing images. Everyone knows what kind of image needs to be captured (yes, I'm talking about you, captcha). Other images don't need capturing—just get the URL and download them. Captchas don't work that way; visiting the same URL again changes the content.

I don't know why Selenium can't just pull the image out of a specific img element; it's so user-hostile.

Based on the materials I found, there are mainly two approaches. One is to simulate mouse operations: right-click on the captcha, then choose Save As, save the captcha locally, and then read it... I don't understand why anyone would come up with such a bizarre approach. A big problem with right-click Save As is that you have no control over where the image is saved, which also means this crawler isn't reusable! So I'll pass on that.

The other approach is to first take a screenshot of the entire page, then based on the position and size of the captcha img element, locate and crop out the small captcha image. Ideally this would work, but after many tests I found that different browsers produce cropped images with different offsets and scaling. I don't know where things went wrong, so I can only hard-code fine-tuning—makes me want to throw up. Even though the method isn't perfect, it's barely good enough. Here's the code...

Code

This time I did it in C# (WinForms). Although it's only a code snippet, the screenshot + crop-and-save part is still worth a look.

The captcha recognition later on was added along the way, using Baidu's API; the accuracy is worrying.

setStatusMsg1("正在提取验证码");
var verifyCode = currentBrowser.WebDriver.FindElement(By.XPath("/html/body/spk-root/spk-login-page/div/section/div[3]/div[2]/div[2]/form/div[3]/div[2]/img"));
setStatusMsg2("浏览器截屏");
// 设置浏览器大小
currentBrowser.WebDriver.Manage().Window.Size = new Size(1280, 800);
// 浏览器截屏
var screenshot = ((ITakesScreenshot)currentBrowser.WebDriver).GetScreenshot();
var screenImagePath = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid().ToString("N")}.jpg");
// 保存截屏图片
setStatusMsg2("保存截屏");
screenshot.SaveAsFile(screenImagePath, ScreenshotImageFormat.Jpeg);

// 裁剪验证码
setStatusMsg2("裁剪验证码");
var codeImagePath = screenImagePath.Replace(".jpg", "_code.jpg");

int x, y, width, height;

// 使用js来获取图片的位置等信息
switch (currentBrowser.BrowserType) {
    case BrowserEnum.Chrome:
        x = Convert.ToInt32((long)((IJavaScriptExecutor)currentBrowser.WebDriver).ExecuteScript("return document.querySelector('body > spk-root > spk-login-page > div > section > div.login-body.clearfix > div.login-right > div.form-con > form > div.qr-code > div.qrcode-box.clearfix > img').x"));
        y = Convert.ToInt32((long)((IJavaScriptExecutor)currentBrowser.WebDriver).ExecuteScript("return document.querySelector('body > spk-root > spk-login-page > div > section > div.login-body.clearfix > div.login-right > div.form-con > form > div.qr-code > div.qrcode-box.clearfix > img').y"));
        width = verifyCode.Size.Width;
        height = verifyCode.Size.Height;
        // 验证码位置调整
        //x += 20;
        //y += 8;
        // 验证码大小调整
        width += 30;
        height += 15;
        break;
    default:
        x = verifyCode.Location.X;
        y = verifyCode.Location.Y;
        width = verifyCode.Size.Width;
        height = verifyCode.Size.Height;
        break;
}

var codeBitmap = new Bitmap(width, height);
var codeGraphics = Graphics.FromImage(codeBitmap);

var destRec = new Rectangle(0, 0, width, height);
var srcRec = new Rectangle(x, y, width, height);
setStatusMsg2(srcRec.ToString());
codeGraphics.DrawImage(new Bitmap(screenImagePath), destRec, srcRec, GraphicsUnit.Pixel);
// 保存验证码图片
codeBitmap.Save(codeImagePath, ImageFormat.Jpeg);

// 显示图片
picVerifyCode.Load(codeImagePath);
picVerifyCode.Tag = codeImagePath;

// 验证码识别
var result = BaiduAiSdk.VerifyCode(codeImagePath);
if (result.Length > 0) {
    txtVerifyCode.Text = result;
    FrmTips.ShowTipsSuccess(this, $"验证码识别成功,识别结果:{result}");

    var input = currentBrowser.WebDriver.FindElement(By.XPath("/html/body/spk-root/spk-login-page/div/section/div[3]/div[2]/div[2]/form/div[3]/div[2]/input"));
    input.Clear();
    input.SendKeys(result);
} else
    FrmTips.ShowTipsError(this, "验证码识别失败,请重试!");

References

Discussion Welcome

Programming Lab focuses on exploring popular new internet technologies and practicing team agile development. Reply with linux, flutter, c#, netcore, android, kotlin, java, python, and so on in the backend of the WeChat official account "Programming Lab" to get related technical articles and materials. If you have any questions, you can also leave a message in the official account backend~

_EOF_

Selenium Scraping in Practice: Capturing Images from a Web Page

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Selenium爬虫实践:ajax请求抓包、浏览器退出

前言 最近在搞公司内部系统,累的一批,需要从另一个内部系统导出数据存到数据库做分析,有大量的数据采集工作,又没办法去直接拿到那个系统的接口,太难了,只能爬虫,但是cookie还经常失效,为了不每次登录失效就来找我重新注入Cookie,我写了一个手机版的网页,用来控制后台的selenium自动登录,截取token和cookie。 ajax请求抓包方案 搜索资料的过程真的痛苦,不过还好这时间没有白花,

2022-05-27 · 爬虫 · 约 1 分钟

一个玄学的爬虫bug竟让我放弃Python语言!?背后的原因令人唏嘘~

每一位成功的程序员,背后也许都站着无数秃头的男人——为其提供各种开发工具&代码库,当然也包括…… 各种玄学bug…… 玄学的开端 最近在用Python做一个爬虫项目的时候遇到一个很奇怪的问题,而且还不是每次都会触发,实在是令人费解…… 报错信息如下: UnicodeEncodeError: 'latin-1' codec can't encode character '\u2026' in pos

2021-12-18 · 爬虫 · 约 1 分钟

爬虫笔记:代理池和线程池

前言 爬虫和反爬虫是一对矛和盾,反爬虫很常见的一个方法就是封IP,一个IP短时间内频繁访问,可以做限流或者是加入黑名单,我之前的后台开发相关博客也有涉及这一块。 不过今天说的是爬虫,所以应对的方法就是用代理池,每次请求都用不同的IP就行,再加上UA模拟,完全是正常用户的行为,可以避开限流和黑名单反爬。 然后爬虫是一种IO密集型程序,如果全程单线程执行那会很慢,因此可以用多线程来提高数据采集效率,不

2022-02-12 · 爬虫 · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…