从网站导入 - 在Mathematica中设置用户代理

18
当我使用Mathematica(Import["mysite","Data"])连接到我的网站并查看我的Apache日志时,我看到:
99.XXX.XXX.XXX - - [22/May/2011:19:36:28 +0200] "GET / HTTP/1.1" 200 6268 "-" "Mathematica/8.0.1.0.0 PM/1.3.1"
当我使用真正的浏览器连接时,是否可以将其设置为以下内容:
99.XXX.XXX.XXX - - [22/May/2011:19:46:17 +0200] "GET /favicon.ico HTTP/1.1" 404 183 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24"
6个回答

12
据我所知,在Mathematica中无法更改用户代理字符串。我曾经使用代理服务器(CNTLM)来让Mathematica与使用NTLM认证的防火墙通信(Mathematica不支持此项认证)。CNTLM还允许您设置用户代理字符串。
您可以在http://cntlm.sourceforge.net/找到它。基本上,您需要在自己的计算机上设置该代理服务器,并在Mathematica网络设置中设置其端口号和IP地址。代理服务器会添加用户代理信息并处理NTLM身份验证。如果您没有NTLM防火墙,则不确定它是如何工作的。还有其他免费代理可供选择,也可能适用于您。
编辑:看起来Squid http代理可以满足您的需求。它具有request_header_replace配置指令,允许您更改请求标头的内容。

3
使用Ragfield的Jlink答案(https://dev59.com/0m025IYBdhLWcg3wsIIU#5862918),我猜你可以构建任何你想要的请求。据我所知,不使用`Import[]`。 - Dr. belisarius
@belisarius 我在我的服务器上安装了Squid代理,我将尝试设置它以更改用户代理。 感谢大家的回答。 - enedene
@enedene 不用谢。代理和J/Link(请参见WReach的答案)解决方案应该都可以使用。选择对你来说更容易的方式吧! - Dr. belisarius
1
对于Squid代理,您可能需要使用request_header_replace设置,例如:request_header_replace User-Agent Nutscrape/1.0 (CP/M; 8-bit) - Sjoerd C. de Vries
是的,我在Squid帮助文档中找到了解决方法。不幸的是,我必须从源代码进行编译,因为要使用request_header_replace功能,需要重新编译Squid并添加--enable-http-violations参数。我可能会在周末尝试这个方案,因为那时候没有人在服务器上使用Squid。 - enedene

11

这里有一种通过JLink使用Apache HTTP客户端的方法:

Needs["JLink`"]

ClearAll@urlString
urlString[userAgent_String, url_String] :=
  JavaBlock@Module[{http, get}
  , http = JavaNew["org.apache.commons.httpclient.HttpClient"]
  ; http@getParams[]@setParameter["http.useragent", MakeJavaObject@userAgent]
  ; get = JavaNew["org.apache.commons.httpclient.methods.GetMethod", url]
  ; http@executeMethod[get]
  ; get@getResponseBodyAsString[]
  ]

你可以按照以下方式使用此函数:
$userAgent =
  "Mozilla/5.0 (X11;Linux i686) AppleWebKit/534.24 (KHTML,like Gecko) Chrome/11.0.696.68 Safari/534.24";

urlString[$userAgent, "http://www.htttools.com:8080/"]

如果需要,您可以将结果提供给ImportString

ImportString[urlString[$userAgent, "mysite"], "Data"]

使用更复杂的代码可以实现流媒体方法,但以上采用基于字符串的方法已足够,除非目标网络资源非常大。

我在Mathematica 7和8中尝试了此代码,并且我预计它也适用于v6。请注意,不能保证Mathematica将来的版本中始终包含Apache HTTP客户端。

工作原理

尽管表述为Mathematica,但解决方案本质上是用Java实现的。Mathematica内置了一个Java运行时环境,并且Mathematica和Java之间的桥梁是称为JLink的组件。

正如这种跨技术解决方案所典型的那样,即使没有太多的代码,也存在相当多的复杂性。本答案的范围超出了详细讨论代码工作原理的范畴,但是有几个项目将强调作为进一步阅读建议。

代码使用Apache HTTP client。选择此Java库是因为它作为标准Mathematica分发的未公开部分而分发-并且它恰好是Import似乎在内部使用的库。

urlString的整个主体都被包装在JavaBlock中。这确保了在操作过程中创建的任何Java对象都由Java和Mathematica内存管理器协调适当释放。

JavaNew 用于创建相关的 Apache HTTP 客户端对象,HttpClientGetMethod。像 http.getParams() 这样的 Java 表达式在 JLink 中表示为 http@getParams[]。Apache HTTP 客户端文档中记录了 Java 类和方法。

使用 MakeJavaObject 有些不寻常。在这种情况下,需要将 Mathematica 字符串作为参数传递,而期望一个 Java Object。如果期望一个 Java String,JLink 将自动创建一个。但是当期望 Object 时,JLink 无法进行推断,因此使用 MakeJavaObject 来给 JLink 提示。

URLTools 怎么样?

顺便提一下,我尝试回答这个问题的第一件事就是使用 Utilities`URLTools`FetchURL。它看起来非常有前途,因为它接受一个名为 "RequestHeaderFields" 的选项。不幸的是,这并没有起作用,因为该函数的当前实现仅将该选项用于 HTTP POST 动词 -- 而不是 GET。也许将来的 Mathematica 版本将支持 GET 的选项。


现在这是一个非常易于使用的解决方案。 不过,我需要寻求帮助来理解它的工作原理。 - enedene
2
@enedene 我添加了一个“工作原理”部分,以指导你需要阅读哪些内容。 - WReach

6
我非常懒惰,使用curl比J/Link更灵活,而且代码更少,避免了对象管理问题。这是一个将数据(userPass)发布到URL并以JSON格式检索结果的示例。
Import["!curl -A Mozilla/4.0 --data " <> userPass <> " " <> url, "JSON"]

我将这种事情隔离在不纯的函数中(除非它是纯的),这样我就知道它是被污染的,但任何网络访问都是这样的。
因为我使用管道,MMA 无法推断文件类型。 ref/Import 提到« Import["!prog","format"] 从管道导入数据。 » 和 « 文件的格式默认从其名称中的文件扩展名或从其内容中的 FileFormat 推断出来。 » 因此,必须指定“CSV”、“JSON”等作为格式参数。否则会看到一些奇怪的结果。
curl 是一个命令行工具,支持 URL 语法传输数据,支持 DICT、FILE、FTP、FTPS、GOPHER、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、POP3、POP3S、RTMP、RTSP、SCP、SFTP、SMTP、SMTPS、TELNET 和 TFTP。curl 支持 SSL 证书、HTTP POST、HTTP PUT、FTP 上传、基于 HTTP 表单的上传、代理、cookie、用户+密码身份验证(Basic、Digest、NTLM、Negotiate、kerberos...)、文件传输恢复、代理隧道和其他大量有用的技巧。

来自{{link1:curl和libcurl欢迎页面}}。


@Mr.Wizard 维基百科有一篇文章:http://en.wikipedia.org/wiki/CUR。此外,`man curl`提供了大量信息(除了Windows以外的任何内容)。实际上,可能提供了太多的信息。 - acl
好的,我已经添加了来自curl/libcurl页面的摘要并添加了链接。他们的话比我的更好。 :-) - Art Taylor

5

Mathematica通过用户指定的代理服务器进行所有的互联网连接。如果像Sjoerd建议的那样,设置一个代理服务器太麻烦了,你可以考虑编写C/C++代码并从Mathematica中调用它。我相信有很多C库可以用几行代码实现你想要的功能。

有关在Mathematica中调用C代码,请参阅C语言接口文档


这也不错。首先我会尝试找一些 Python 的东西,因为我比 C 更熟悉 Python。 - enedene
好的,就我的目的而言我发现我可以从Mathematica运行外部程序,所以我将用Python编写代码,然后只需导入Python作为输出得到的字符串并使用Mathematica处理其余部分。谢谢大家,你们所有人都提供了有趣的解决方案,这将扩大我在未来问题上可实现的解决方案集合。 - enedene

4

Mathematica 9增加了新的URLFetch函数。它有UserAgent选项。


2
你可以使用 J/Link 进行 Web 请求或在命令行上调用 curl 或 wget。

2
请问您能否提供一个使用J/Link修改用户代理的示例? - Dr. belisarius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接