- 后端
- 网页爬虫
【免费下载链接】webmagic
A scalable web crawler framework for Java.
webmagic-scripts 是 WebMagic 爬虫框架(Java)中的一个实验性子模块,它让你不写 Java 代码,只用一段简单的脚本(默认 JavaScript,也支持 Ruby/JRuby)即可完成页面抽取、链接发现与结果输出。本文以 webmagic-scripts/README.md 为主体,结合模块源码,完整讲解脚本 API、控制台命令行用法、多语言机制与底层执行原理,读完你既能直接运行别人写好的脚本,也能自己编写并流通一套抓取脚本。
一、设计目标:让爬虫脚本可编写、可流通
模块的目标非常明确:用简单脚本的方式编写爬虫,为一些常用场景提供"可流通"的脚本——如果已经有人写好了脚本,你直接使用即可,无需下载依赖、编写 Java 代码,也不需要经历编译打包流程。
从仓库结构看,该模块位于 webmagic-scripts,其 pom.xml 依赖webmagic-core、webmagic-extension,并通过maven-jar-plugin将主类配置为us.codecraft.webmagic.scripts.ScriptConsole,这正是"控制台一键运行"能力的来源。它同时引入jruby、jython、commons-cli等依赖,对应着多语言引擎支持与命令行参数解析。
二、快速上手:控制台运行一个抓取脚本
原文档提供了一个控制台版本(webmagic-console压缩包)。解压后,使用如下命令执行脚本:
java -jar -Dfile.encoding='utf-8' webmagic-console.jar -f 脚本文件名 [-l 语言,默认是javascript] [-t 线程数] [-s 抓取间隔,毫秒] url1 url2 …各参数含义如下表:
| 参数 | 含义 | 默认值 |
|---|---|---|
-f | 脚本文件名(必填) | 无 |
-l | 脚本语言,javascript或ruby | javascript |
-t | 抓取线程数 | 1 |
-s | 两次请求之间的抓取间隔(毫秒) | 1000 |
| 位置参数 | 起始 URL,可多个(url1 url2 …) | 无 |
例如,对仓库中自带的 js/github.js 脚本,可以这样执行:
java -jar -Dfile.encoding='utf-8' webmagic-console.jar -f github.js -t 2 -s 0 https://github.com/code4craft该命令以 2 个线程、0 毫秒抓取间隔,从https://github.com/code4craft开始抓取 GitHub 仓库数据。注意-Dfile.encoding='utf-8'用于保证脚本文件以 UTF-8 编码读取,避免中文或特殊字符乱码。
从源码看,控制台入口 ScriptConsole.java 会依次完成:解析命令行参数 → 用ScriptProcessorBuilder构建ScriptProcessor→ 配置Site(设置sleepTime、重试次数 3,接受状态码集合200/404/403/500/502)→ 创建Spider并添加起始 URL →spider.run()启动抓取。若未提供任何 URL,程序会打印用法提示并以-1退出。
三、脚本 API:三个核心函数与 page 对象
脚本之所以"简单",是因为模块预先注入了少量开箱即用的辅助函数。JavaScript 的辅助函数定义在 js/defines.js:
function $(str){ return page.getHtml().$(str).toString(); } function xpath(str){ return page.getHtml().xpath(str).toString(); } function urls(str){ links = page.getHtml().links().regex(str).all(); page.addTargetRequests(links); }即脚本中可直接使用三个全局函数:
$(cssSelector):按 CSS 选择器抽取页面元素并转为字符串;xpath(xpathExpr):按 XPath 表达式抽取页面元素并转为字符串;urls(regex):从当前页面所有链接中匹配正则,将命中的 URL 作为后续抓取目标(对应 WebMagic 的"目标请求"机制,实现自动翻页/发现新页面)。
Ruby 的辅助函数定义在 ruby/defines.rb,除xpath、urls外还额外提供了css函数;Python 的辅助函数定义在 python/defines.py,同样提供xpath、css、urls。
除了辅助函数,脚本运行环境中还注入了两个关键对象(见 ScriptProcessor.java 的process方法):
page:us.codecraft.webmagic.Page实例,可直接调用page.getUrl()、page.getHtml()、page.addTargetRequests(...)等 WebMagic 原生方法;config:Site实例,用于在脚本中调整抓取配置。
在 JavaScript 中访问这些对象直接用page.xxx;在 Ruby 中则通过$page等全局变量(defines.rb 中的$page.getHtml()),两种语言的约定略有差异,使用时需注意。
四、实例解析:用 JavaScript 抓取 GitHub 仓库数据
原文档给出了抓取 GitHub 仓库数据的 JavaScript 脚本(即仓库中的 js/github.js):
var name=xpath("//h1[@class='entry-title public']/strong/a/text()") var readme=xpath("//div[@id='readme']/tidyText()") var star=xpath("//ul[@class='pagehead-actions']/li[1]//a[@class='social-count js-social-count']/text()") var fork=xpath("//ul[@class='pagehead-actions']/li[2]//a[@class='social-count']/text()") var url=page.getUrl().toString() if (name!=null){ println(name) println(readme) println(star) println(url) } urls("(https://github\\.com/\\w+/\\w+)") urls("(https://github\\.com/\\w+)")逐行拆解:
- 字段抽取:用
xpath(...)分别抽取仓库名(name)、README 正文(readme,通过 WebMagic 的tidyText()提取干净文本)、Star 数与 Fork 数; - 页面 URL:
page.getUrl().toString()拿到当前页面地址; - 条件输出:只有当
name != null(即命中仓库详情页而非个人主页)时才输出结果,借助 JavaScript 引擎自带的println打印到控制台; - 链接发现:
urls("(https://github\\.com/\\w+/\\w+)")匹配形如"用户/仓库"的详情页链接,urls("(https://github\\.com/\\w+)")匹配个人主页链接,两者共同驱动 Spider 自动扩散抓取范围。
这段脚本展示了脚本式爬虫的典型"抽取-输出-发现"三段式写法,无需任何 Java 类定义,直接交给控制台运行即可。
仓库中还提供了另一个 JavaScript 示例 js/oschina.js,它用$("div.BlogTitle h1")这种 CSS 写法抽取博客标题,并通过urls("http://my\\.oschina\\.net/flashsword/blog/\\d+")发现后续博客列表页,同时演示了脚本内定义config对象(可携带ua、sleepTime等配置项)的写法。
五、多语言支持:Ruby/JRuby 与语言参数
原文档说明,选用 JavaScript 是因为用户面广;选用 Ruby 则是因为Ruby 语法编写 DSL 更简洁。Ruby 版本(ruby/github.rb):
name= xpath "//h1[@class='entry-title public']/strong/a/text()" readme = xpath "//div[@id='readme']/tidyText()" star = xpath "//ul[@class='pagehead-actions']/li[1]//a[@class='social-count js-social-count']/text()" fork = xpath "//ul[@class='pagehead-actions']/li[2]//a[@class='social-count']/text()" url=$page.getUrl().toString() puts name,readme,star,fork,url unless name==nil urls "(https://github\\.com/\\w+/\\w+)" urls "(https://github\\.com/\\w+)"Ruby 版本省略了函数调用括号,xpath "..."、urls "..."的写法更接近自然语言 DSL;输出使用 Ruby 的puts,条件输出使用unless name==nil。注意 Ruby 脚本中页面对象通过$page访问。
多语言通过-l参数区分。例如执行这个 Ruby 脚本:
java -jar -Dfile.encoding='utf-8' webmagic-console.jar -f github.rb -t2 -s0 -l ruby https://github.com/code4craft从 Params.java 的源码看,语言别名映射为:
-l取值 | 对应引擎 |
|---|---|
js、javascript、JavaScript、JS | JavaScript |
ruby、jruby、Ruby、JRuby | JRuby |
此外,虽然原文档只提到 JavaScript 与 Ruby,仓库中实际上还内置了Jython(Python)语言实现(Jython.java),并有示例脚本 python/oschina.py。同时,模块的 [pom.xml](https://link.gitcode.com/i/a1512246080de2e02b654296c0274dc0) 中还引入了 Kotlin 与 Groovy 支持([Github.kt](https://link.gitcode.com/i/6b9a9e42d296e437002be1031fdd38c3) 演示了 Kotlin 编写标准 PageProcessor 的写法,[Github.groovy](https://link.gitcode.com/i/d2cd080be00e479623eb64456304ad22) 演示了 Groovy DSL 风格配置Site` 与抽取规则的写法),可见多语言是其设计主线之一。
六、源码级原理:ScriptEngine、EnginePool 与执行链路
原文档说明"这部分使用 Java 的 ScriptEngine 机制完成"。深入源码可以看到完整的执行链路:
1. 处理器(ScriptProcessor):ScriptProcessor.java 实现 WebMagic 的PageProcessor接口。process(Page page)方法从ScriptEnginePool借出一个引擎,将page与config(即Site)注入ScriptContext.ENGINE_SCOPE,然后调用language.process(engine, defines, script, page)执行"辅助函数定义 + 用户脚本",最后把引擎归还池中。
2. 语言抽象(Language):Language.java 是抽象基类,每个实现类绑定三要素:引擎名称(engineName)、辅助函数定义文件(defineFile,如js/defines.js)、结果收集文件(gatherFile)。Javascript.java 直接engine.eval(defines + "\n" + script),把辅助函数和用户脚本拼接后整体求值;而 JRuby.java 会捕获求值返回的RubyHash,将其迭代写入page.getResultItems(),这就是 Ruby 脚本天然"以字典形式返回结果"的底层原因。
3. 引擎池(ScriptEnginePool):ScriptEnginePool.java 按线程数预创建 N 个ScriptEngine(通过ScriptEngineManager.getEngineByName(language.getEngineName())),用LinkedBlockingQueue维护,getEngine()出队、release()入队,并用AtomicInteger统计可用数量——这保证了多线程抓取时每个线程有独立脚本引擎,避免引擎状态互相污染。
4. 测试佐证:ScriptProcessorTest.java 分别用Javascript、JRuby、Jython三种语言加载 classpath 下的 oschina 脚本,配合Spider.create(pageProcessor)实际抓取并校验执行流程(该测试类标注@Ignore,属于需要联网环境的集成性测试)。
七、以库的形式集成:ScriptProcessorBuilder
除了控制台,脚本能力也能作为 Java 库直接嵌入自己的程序。构建器 ScriptProcessorBuilder.java 提供链式 API:
custom():创建构建器,默认语言为 JavaScript,默认线程数 1;language(Language):指定语言(new Javascript()/new JRuby()/new Jython());scriptFromFile(fileName):从文件系统读取脚本;scriptFromClassPathFile(fileName):从 classpath 读取脚本(如js/oschina.js);script(String):直接传入脚本源码字符串;thread(int):设置引擎池线程数;build():构建ScriptProcessor。
参考 ScriptProcessorTest.java 的用法:
ScriptProcessor pageProcessor = ScriptProcessorBuilder.custom() .language(new Javascript()) .scriptFromClassPathFile("js/oschina.js") .build(); pageProcessor.getSite().setSleepTime(0); Spider.create(pageProcessor).addUrl("http://my.oschina.net/flashsword/blog").setSpawnUrl(false).run();build()后得到的是标准PageProcessor,可直接交给Spider.create(...)使用,与 WebMagic 原有 API 无缝衔接。
八、进阶:命令行参数解析与日志级别
控制台的参数解析由 CommandLineOption.java 实现(基于 commons-cli),实际支持 5 个选项:
| 选项 | 作用 |
|---|---|
-l | 语言,交给Params.setLanguagefromArg做别名匹配 |
-f | 脚本文件路径 |
-s | 抓取间隔(毫秒),Integer.parseInt解析 |
-t | 线程数,Integer.parseInt解析 |
-g | 日志级别,交给 ConfigLogger.java 处理 |
-g可取值包括debug、info、warn、trace、off、error(大小写不敏感),通过设置 SLF4J root logger 的日志级别来控制控制台输出详略,便于排查脚本问题。
从 Params.java 还可确认各参数默认值:语言默认Javascript、线程数默认 1、抓取间隔默认 1000 毫秒,与 README 描述一致。
九、注意事项与实验状态
原文档明确指出:这个功能目前仍在实验阶段。因此在实际使用中需要了解以下前提与限制:
- 依赖运行时环境:JavaScript 依赖 JDK 自带的 Nashorn 等 ScriptEngine 实现;Ruby、Python 支持依赖
jruby、jython依赖包(见 pom.xml),引擎是否可用取决于你的 Java 版本与 classpath; - 脚本运行于沙箱之外:脚本本质是在 JVM 内直接求值,可访问注入的
page、config对象,请勿运行来源不可信的脚本; - 实验性 API:辅助函数集合、结果收集方式(Ruby 的 Hash 返回、Python 的
result字典)在不同语言间并不完全统一,升级 WebMagic 版本时脚本可能需要相应调整; - 控制台方式:仓库以
webmagic-scriptsMaven 模块形式提供源码与构建配置,主类为ScriptConsole;如需控制台版 jar 包,可自行构建该模块获取。
总体而言,webmagic-scripts 以"脚本即爬虫"的思路大幅降低了 WebMagic 的使用门槛,让常用抓取场景沉淀为一行命令即可运行的脚本资产。无论是快速验证抽取规则、临时抓取数据,还是向团队流通标准化的抓取脚本,它都是一条值得尝试的轻量路径。
- 后端
- 网页爬虫
【免费下载链接】webmagic
A scalable web crawler framework for Java.
相关推荐
WebMagic 爬虫框架使用教程
WebMagic 爬虫框架使用教程 项目介绍 WebMagic 是一个简单灵活的 Java 爬虫框架,它基于模块化设计,易于扩展和维护。WebMagic 提供了
后端网页爬虫终极指南:用eSearch免费离线OCR轻松识别古籍竖排文字
终极指南:用eSearch免费离线OCR轻松识别古籍竖排文字 还在为古籍文献、书法作品的文字识别而烦恼吗?传统OCR工具面对竖排文字时常常束手无策,识别结果混乱
桌面应用OCR屏幕录制视频处理图像处理从封禁到稳定:WebMagic爬虫速率控制完全指南
从封禁到稳定:WebMagic爬虫速率控制完全指南 你是否曾因爬虫请求过于频繁导致IP被封禁?是否遇到过目标网站反爬机制导致数据抓取不稳定?本文将通过WebMa
后端网页爬虫
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考