深度解析爬虫(python+requests、python+selenium、golang)

什么是爬虫?

爬虫实际上就是采集网络上数据的一段程序。
简单来说,爬虫程序通过请求url地址,然后根据响应的内容进行数据采集。如果响应内容是html,分析dom结构,进行dom解析或者正则匹配,如果响应内容是xml/json数据,转换数据对象,然后对数据进行解析。

采集数据的用途

采集数据就是将别人的资源采集下来,然后加以利用,变为自己的资源。我们可以从某些网站获取需要的图片、数据、文章放到自己的网站中,也可将网站中的热点采集下来,进行数据分析。

Beautiful Soup 是一个常用的网页解析器,可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。

Beautiful Soup文档链接 https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/#

爬虫注意事项

在很多网站中,通常会存在反爬操作,来阻止网站数据被爬取。如果长时间频繁的使用爬虫爬取某些网站数据,容易造成IP被封情况。因此,为降低IP被封,而导致爬取数据失败的几率,可使用随机user-agent,以及ip代理,和注意每次爬虫的时间间隔。

一、requests

requests是python实现爬虫功能中简单易用的HTTP库,也是爬虫过程中常用的一种工具库,操作简单,通过pip install requests命令进行安装,即可使用。但同样也存在某些不足之处,比如在爬取某些js动态加载的网页数据时,就容易爬取不到相关数据。此时,可以尝试使用selenium进行数据爬取工作。

# -*- coding: UTF-8 -*-
import requests,json
from bs4 import BeautifulSoup
# ip代理
proxies = {
  "http": "http://171.12.115.194:9999",
  "https": "http://171.12.115.194:9999",
}

class RequestsData():
    def __init__(self,url):
        self.url = url
        self.headers={
                'User-Agent':'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
            }
        resp = requests.get(self.url, headers=self.headers,proxies=proxies,verify=False)
        if resp.status_code != 200:
            return
        self.soup = BeautifulSoup(resp.text, 'html.parser', from_encoding='utf-8')
    def getData(self):
        div = self.soup.find("div",class_="market-bd market-bd-6 course-list course-card-list-multi-wrap js-course-list")
        ul = div.find("ul",class_="course-card-list")
        lis = ul.select("li")
        return lis
    def getSideData(self):
        contents = json.loads(self.soup.contents[0])
        data = contents["result"]["bottom_list"]
        return data

if __name__ == '__main__':
    obj = RequestsData(url='https://ke.qq.com/cgi-bin/course/courseListOtherModule?mt=0&bkn=1372242365&r=0.6038976779720526')
    data = obj.getSideData()
    # obj=RequestsData(url='https://ke.qq.com/course/list/golang?page=1')
    # data = obj.getData()
二. selenium

selenium 是一个用于Web应用程序测试的工具,通过调用相应浏览器的驱动程序,模拟用户进行操作。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。
Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。
selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。

Headless Chrome
Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有Chrome支持的特性,在命令行中运行你的脚本。以前在爬虫要使用Phantomjs来实现这些功能,但Phantomjs已经暂停开发,现在可以使用Headless Chrome来代替。

同样,selenium作为爬虫的工具库之一,虽然能够模拟用户打开浏览器进行访问,但也同样存在不足的地方,比如爬虫数据的时间比其他工具库要长,并且使用也比较繁琐,需要下载相应浏览器版本的驱动,否则,你可能会看到浏览器刚开启,就关闭的场景。

selenium中文文档链接:https://selenium-python-zh.readthedocs.io/en/latest/
查找chrome浏览器对应版本的chromedriver,下载chromedriver 链接http://npm.taobao.org/mirrors/chromedriver/,查看chrome浏览器版本相关信息,在地址栏输入chrome://version/即可

# -*- coding: UTF-8 -*-

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
import random

class SeleniumData(object):
    def __init__(self,url='http://www.baidu.com/'):
        # 设置chrome为headless模式
        # chrome_options = webdriver.ChromeOptions()
        # chrome_options.add_argument('--headless')
        # self.browser = webdriver.Chrome(chrome_options=chrome_options)

        # 默认可视化界面模式
        self.browser = webdriver.Chrome()
        self.url = url


    def getTengXunKeTang(self):
        self.browser.get(self.url)
        self.browser.find_element_by_id("js_keyword").send_keys("golang")
        sleep(1)
        self.browser.find_element_by_id("js_search").click()
        sleep(1)
        data = []
        courseCardList = self.browser.find_element_by_class_name("course-card-list")
        lis = courseCardList.find_elements_by_class_name("js-course-card-item")
        for li in lis:
            temp = {}
            a = li.find_element_by_tag_name("a")
            temp["url"] = a.get_attribute("href")
            title = li.find_element_by_class_name("item-tt").text
            temp["title"] = title
            temp["img"] = a.find_element_by_tag_name("img").get_attribute("src")
            data.append(temp)
            print temp
            sleep(1)
        print 1111111,len(data)

    def openBaiduLoginFrame(self):
        # 百度登录爬虫处理
        self.browser.get(self.url)
        self.browser.find_element_by_id("u1").find_element(By.NAME,"tj_login").click()
        sleep(1)
        self.browser.find_element(By.ID,"TANGRAM__PSP_11__footerULoginBtn").click()
        self.browser.find_element_by_id("TANGRAM__PSP_11__userName").send_keys("1805656666")
        sleep(1)
        self.browser.find_element_by_id("TANGRAM__PSP_11__password").send_keys("**********")
        sleep(1)
        self.browser.find_element_by_id("TANGRAM__PSP_11__submit").click()
        sleep(1)
        a = []
        i = 1
        while True:
            try:
                i = i + 1
                if i == 1000:
                    break
                b = random.choice([45,127,90,180,360])
                self.browser.execute_script("document.getElementByClassName('vcode-spin-button').style.transform=translateX("+str(b)+"px);")
                sleep(0.5)
            except Exception,e:
                continue
            a = a.append(b)
        print a

    def browserClose(self):
        self.browser.quit()

if __name__ == '__main__':
    obj = SeleniumData(url="https://ke.qq.com/")
    obj.getTengXunKeTang()
    obj.browserClose()
    # sleep(3)
    # baiduObj = SeleniumData()
    # baiduObj.openBaiduLoginFrame()
    # baiduObj.browserClose()

三、golang

通常爬虫,我们首先想到的可能是用python进行数据爬取,其实爬虫并不局限于开发语言,golang也同样可以爬取数据,原理和以上所述相同,都是获取url地址的响应内容,进行解析。
同样,前端js也可以做爬虫程序,去采集相关数据,如使用axios爬取数据,此处不做示例分析。
以下为通过golang做爬虫程序的示例,仅供参考。

package main

import (
    "time"
    "math/rand"
    "strings"
    "net/http"
    "fmt"
    "github.com/go-xweb/log"
    "io/ioutil"
    "encoding/xml"
    "regexp"
)

var userAgent = [...]string{"Mozilla/5.0 (compatible, MSIE 10.0, Windows NT, DigExt)",
    "Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, 360SE)",
    "Mozilla/4.0 (compatible, MSIE 8.0, Windows NT 6.0, Trident/4.0)",
    "Mozilla/5.0 (compatible, MSIE 9.0, Windows NT 6.1, Trident/5.0,",
    "Opera/9.80 (Windows NT 6.1, U, en) Presto/2.8.131 Version/11.11",
    "Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, TencentTraveler 4.0)",
    "Mozilla/5.0 (Windows, U, Windows NT 6.1, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/5.0 (Macintosh, Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
    "Mozilla/5.0 (Macintosh, U, Intel Mac OS X 10_6_8, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/5.0 (Linux, U, Android 3.0, en-us, Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
    "Mozilla/5.0 (iPad, U, CPU OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, Trident/4.0, SE 2.X MetaSr 1.0, SE 2.X MetaSr 1.0, .NET CLR 2.0.50727, SE 2.X MetaSr 1.0)",
    "Mozilla/5.0 (iPhone, U, CPU iPhone OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
    "MQQBrowser/26 Mozilla/5.0 (Linux, U, Android 2.3.7, zh-cn, MB200 Build/GRJ22, CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"}

var urlChannel = make(chan string, 200) //chan中存入string类型的href属性,缓冲200
var atagRegExp = regexp.MustCompile(`<a[^>]+[(href)|(HREF)]\s*\t*\n*=\s*\t*\n*[(".+")|('.+')][^>]*>[^<]*</a>`) //以Must前缀的方法或函数都是必须保证一定能执行成功的,否则将引发一次panic
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
func GetRandomUserAgent() string {
    return userAgent[r.Intn(len(userAgent))]
}

func Spider(url string){
    defer func() {
        if r := recover(); r != nil {
            log.Println("[E]", r)
        }
    }()
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("User-Agent", GetRandomUserAgent())
    client := http.DefaultClient
    res, e := client.Do(req)
    if e != nil {
        fmt.Errorf("Get请求%s返回错误:%s", url, e)
        return
    }

    if res.StatusCode == 200 {
        body := res.Body
        defer body.Close()
        bodyByte, _ := ioutil.ReadAll(body)
        resStr := string(bodyByte)
        atag := atagRegExp.FindAllString(resStr, -1)
        for _, a := range atag {
            href,_ := GetHref(a)
            if strings.Contains(href, "article/details/") {
                fmt.Println("☆", href)
            }else {
                fmt.Println("□", href)
            }
            urlChannel <- href
        }
    }
}

func GetHref(atag string) (href,content string) {
    inputReader := strings.NewReader(atag)
    decoder := xml.NewDecoder(inputReader)
    for t, err := decoder.Token(); err == nil; t, err = decoder.Token() {
        switch token := t.(type) {
        // 处理元素开始(标签)
        case xml.StartElement:
            for _, attr := range token.Attr {
                attrName := attr.Name.Local
                attrValue := attr.Value
                if(strings.EqualFold(attrName,"href") || strings.EqualFold(attrName,"HREF")){
                    href = attrValue
                }
            }
            // 处理元素结束(标签)
        case xml.EndElement:
            // 处理字符数据(这里就是元素的文本)
        case xml.CharData:
            content = string([]byte(token))
        default:
            href = ""
            content = ""
        }
    }
    return href, content
}

func main(){
    Spider("https://blog.csdn.net/")
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352