一次失败的爬虫实战(一)

【记录】记一次颇为坎坷的爬虫实战,前期还算一切顺利

上周有个要好的研究生朋友找我帮忙,她最近开始准备毕业论文,需要收集一些数据。我立马就答应了,毕竟是关系很好的老同学了,怎么能不伸出援手。不过还是有些感慨,在同学眼里,学计算机好像是万能的:无论是修电脑、买电脑、做APP、咨询游戏机、爬数据,都得是样样精通。

当然我还是很愿意做这件事的,因为这对我来说也是一次很好的锻炼,一次爬虫实战,能锻炼很多方面的技术,比如:多线程、字符处理、设计思路、数据结构等等,可以说是一次综合能力的锻炼。

当然爬不同的数据难度不一样,简单了解了一下,发现要从一个官网上下载某类别下的2019年的文档,并分析内容,生成Excel。听完倒是觉得不难,便欣然立下了flag:“没问题,等我好消息”。说干就干,马上开工:

1. 获取数据

第一步就是上官网,看怎么获取数据,本以为是像之前一样,分析html页面中的数据,检索关键词。没想到比这更简单,直接调用某个接口返回json数据,甚至pagesize可以直接填1000,一次请求就能抓取全部想要的数据。这里不得不吐槽这个不对页面大小做限制也太离谱了。。。

//Run 执行爬虫 比如读取10页的数据,开启十个协程并发处理,并使用wg.Wait() 阻塞等待所有协程结束    
func (s *Security) Run(begin int, end int) {
    fmt.Printf("[Crawler] %s running ...\n", s.Name)
    timeNow := time.Now().UnixNano()
    for i := begin; i <= end; i++ {
        s.wg.Add(1)
        go s.GetRequest(i, client)
    }
    s.wg.Wait()
    fmt.Printf("[Crawler] %s find %d items |run time %d ms\n", s.Name, len(s.Result), (time.Now().UnixNano()-timeNow)/1e6)
}
//GetRequest 爬虫核心代码
func (s *Security) GetRequest(page int, client *http.Client) {
    //拼接页数 得到url
    url := fmt.Sprintf("%s%d", s.URL, page)
    fmt.Println(url)
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Println("获取地址错误")
        return
    }

    //设置请求头,尽量模仿真人请求
    req.Header = s.Header
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("get请求错误", err)
        return
    }
    defer s.wg.Done()
    defer resp.Body.Close()

    //读取body数据
    response, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println("ioutil ReadAll failed :", err.Error())
        return
    }
}

2. 解析数据

拿到数据后就是解析json数据了,go语言自带的解析工具很好用,首先定义好对应的结构体类型(不需要的数据无需定义),然后调用json.Unmarshal()

//JSONCallBacks json结构 可以绑定json和form类型
type JSONCallBacks struct {
    Result []ResultData `json:"data" form:"data"`
}
//ResultData 实际数据结构,并非真实数据
type ResultData struct {
    //自增ID 存数据库用
    ID int `gorm:"primary_key"`
    Date string
    URL string
    Title string
}

obj := utils.JSONCallBacks{}
err = json.Unmarshal(response, &obj)
if err != nil {
    log.Println("decode json data failed :", err.Error())
    return
}

3. 保存数据

数据解析完成之后,就是保存数据了,由于是一条一条的记录,使用数据库保存是个很好的方法。因为已经定义了json结构,使用gorm保存到数据库非常容易

for _, v := range obj.Result {
    //*gorm.DB
    utils.DB.Create(&v)
}

4. 下载文件

根据url下载pdf文件,这步开始感觉出不对了,所有文档都是pdf结构的,无法像txt那种轻易解析,就决定先下载下来再解析。说到下载文件,就想到了python。。。

# coding = UTF-8
# 下载txt中的所有链接,没错,网上随便抄的一段代码。。。
import urllib.request
import re
import os

# 从文本中读取链接
def getUrl():
    list = [ ]
    count = 0
    for line in open("recordback.txt"):   
        count = count + 1
        list.append(line.strip())
    print(count)
    return(list)

# 下载全部连接
def getFile(url):
    file_name = url.split('/')[-1]
    u = urllib.request.urlopen(url)
    f = open(file_name, 'wb')

    block_sz = 8192 * 4
    while True:
        buffer = u.read(block_sz)
        if not buffer:
            break

        f.write(buffer)
    f.close()
    print ("Sucessful to download" + " " + file_name)

# 从文本中读取链接
url_lst = getUrl()

# 新建文件夹
os.chdir(os.path.join(os.getcwd(), 'pdf'))

# 下载列表中的所有文件
for url in url_lst[:]:
    print(url)
    getFile(url)

目前为止一切都是那么的顺利,成功读取了全部文档信息,并保存到了数据库,也成功下载了pdf文件。接下来就是读取pdf内容,并分析其中的数据。等等,似乎感觉哪里不太对。。。

Licensed under CC BY-NC-SA 4.0
加载中...
感谢Jimmy 隐私政策