文章目录
- 一、http client
- 爬取并存储 jpg
用 golang 可以很方便的爬图(http 下载图片,存储为 jpg 格式)。
一、http client
http client 有如下最佳实践:
- 尽量用 default http client:默认的 http client 设置了很多合适的参数(如超时、连接池),也便于在各请求间复用(如先将获取到的 token 存储到 client 内,后续所有请求都可用此 token)
- 要设置 timeout:防止因网络 or 下游 server 的问题,而盲等,导致自己阻塞,降低拥堵体验
- 谨慎处理 redirects:若 server 不存在某资源时可能会用 3xx redirect 到新目的地。然而若 client 未合适处理,可能导致 loop redirect。因此需要如下做法:
- 校验 redirect url
- 限制 redirect 次数
- reuse connections:可用连接池实现,可减少新建连接的开销、降低延迟、增加流量。
- 默认会打开 Keep-Alive,除非需求是在一个连接上的数据请求密度不高则可手动关闭。详见实验
爬取并存储 jpg
package clients
import (
"fmt"
"github.com/sirupsen/logrus"
"gitlab.deepglint.com/yuchuansun/petroltools/configs"
"io"
"net/http"
"os"
"strings"
"time"
)
var httpCli = &http.Client{
Timeout: 10 * time.Second,
}
type spiderCli struct {
httpCli *http.Client
txtFile *os.File
}
func Spider() *spiderCli {
txtFile, err := os.OpenFile(configs.TxtFileName(), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
logrus.Fatal(err)
}
return &spiderCli{
httpCli: httpCli,
txtFile: txtFile,
}
}
func (c *spiderCli) Download(url string) ([]byte, error) {
res, err := c.httpCli.Get(url)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode == http.StatusNotFound {
return nil, fmt.Errorf("got invalid status code: %v", res.StatusCode)
}
return io.ReadAll(res.Body)
}
// Save img.jpg and txt
func (c *spiderCli) Save(fid int64, bytes []byte, plateText, plateColor, plateType string) error {
// img
fImgName := fmt.Sprintf("%v.jpg", fid)
fImg, err := os.Create(fImgName)
if err != nil {
return err
}
defer fImg.Close()
writtenImg, err := fImg.Write(bytes)
if err != nil {
return err
}
if writtenImg == 0 {
os.Remove(fImgName)
}
// txt
line := strings.Join([]string{fImgName, plateText, plateColor, plateType}, ",")
writtenTxt, err := c.txtFile.WriteString(line + "\n")
_ = writtenTxt
return err
}
func (c *spiderCli) Close() {
c.txtFile.Close()
}