我正在尝试下载一个html页面,然后使用Racket在其上运行一个正则表达式。这适用于某些页面但不适用于其他页面。我最终解决了这个问题是因为有些页面被gzip压缩并发出HTTP GET请求,get-pure-port提供了gzip压缩页面,当然看起来像乱码。
我的问题:有没有办法在球拍中解压缩页面,以便我可以在其上运行正则表达式?
谢谢。
答案 0 :(得分:5)
虽然行为良好的Web服务器不会为您提供gzip响应,除非您为它们提供了Accept-Encoding: gzip
请求标头,但并非每个Web服务器都表现良好。
因此,您需要查找Content-Encoding: gzip
响应标头并使用gunzip-through-ports
。 (您可以对Content-Encoding: deflate
和inflate
执行相同操作。)
当然,要“查找响应标头”,您不能再使用get-pure-port
了,您必须使用get-impure-port
和purify-port
。伪代码:
#lang racket
(require net/url
net/head
file/gunzip)
(define u (string->url "http://www.wikipedia.org"))
(define in (get-impure-port u '("Accept-Encoding: gzip")))
(define h (purify-port in))
(define out (open-output-bytes))
(match (extract-field "Content-Encoding" h)
["gzip" (gunzip-through-ports in out)]
[_ (copy-port in out)])
(define bstr (get-output-bytes out))
(close-input-port in)
P.S。我认为上面第一次尝试时更容易探索。但是对于生产代码I'd probably use call/input-url
来帮助处理关闭端口:
#lang racket
(require net/url
net/head
file/gunzip)
(define u (string->url "http://www.wikipedia.org"))
(define bstr
(call/input-url u
(curryr get-impure-port '("Accept-Encoding: gzip"))
(lambda (in)
(define h (purify-port in))
(define out (open-output-bytes))
(match (extract-field "Content-Encoding" h)
["gzip" (gunzip-through-ports in out)]
[_ (copy-port in out)])
(get-output-bytes out))))
p.p.s。
如果它没有使用curryr
和匿名函数,那么该版本可能会更清晰。例如:
#lang racket
(require net/url
net/head
file/gunzip)
;; Like get-impure-port, but supplied Accept-Encoding gzip request
;; header.
(define (get-impure-port/gzip u)
(get-impure-port u '("Accept-Encoding: gzip")))
;; Read response headers using purify-port, and read the response
;; entity handling gzip encoding.
(define (read-response in)
(define h (purify-port in))
(define out (open-output-bytes))
(match (extract-field "Content-Encoding" h)
["gzip" (gunzip-through-ports in out)]
[_ (copy-port in out)])
(get-output-bytes out))
(define bstr
(call/input-url (string->url "http://www.wikipedia.org")
get-impure-port/gzip
read-response))