一文入坑——爬虫

2021-04-21 3,703


“网络爬虫”又称“网络蜘蛛”,是一种在互联网上自动采集数据的自动化程序。爬虫的规模可大可小,大到百度、谷歌搜索,小到文本采集、自动采集图片等。


1获取目标地址


下面介绍如何获取准备爬取内容的URL。以阿里云漏洞预警页面为例,我们要得到的是漏洞预警标题、同标题URL、漏洞预警公告时间等信息。图1中URL就是我们准备爬取的地址:


1.png


可获取目标的Python爬虫代码片段如下:


#获取目标

urls = ['https://help.xxxxxx.com/n***/92****/{}.html'.format(str(i)) for i in range(0,2,1)]

    for url in urls:

        html = get_html(url)

其爬取结果如图2所示:


2.png

爬虫的本质是网络请求,在请求一个网页获得响应后获取html源码,接着处理获取到的html源码,并提取想要的数据,如图3所示。

3.png

出于降低编程难度以及代码重用等方面的考虑,通常将每个功能封装为一个个函数。


2获取当前URL的HTML


图4就是我们需要的HTML内容,我们将通过python的requests库对其进行获取。


E6pMhLXI_gQ47.png


通过requests库获取目标页面的HTML源码如下所示。考虑到代码比较容易理解,所以不在此处做过多说明。

import requests

def get_html(url):

    '''

    获得 HTML

    '''

    headers = {

        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53\

        7.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'

    }

    response = requests.get(url, headers=headers)

    if response.status_code == 200:

        response.encoding = 'utf-8'

        return response.text

    else:

        return


从上述的源码可以看出,我们可通过requests库的get函数直接获取到目标页面的HTML源码。


requests库的的其他常用方法如图5所示。

0BIZ6TEWd_6abE.png


另外,在使用requests库时,我们还可以添加一些字段,如表1所示。


表1

params

字典或字节序列,作为参数增加到url中

data

字典、字节序列或文件对象,作为Request的内容

json

JSON格式的数据,作为Request的内容

headers

字典,HTTP定制头

cookies

字典或CookieJar,Request中的auth : 元组支持HTTP认证功能

files

字典类型,传输文件

timeout

设定超时时间,秒为单位

proxies

字典类型,设定访问代理服务器,可以增加登录认证

allow_redirects

True/False,默认为True,重定向开关

stream

True/False,默认为True,获取内容立即下载开关

verify

True/False,默认为True,认证SSL证书开关

cert

本地SSL证书

auth

元组,支持HTTP认证功能


使用参数cookies、proxite与verify的代码示例如下:


· 小例子

· cookies = {'cookies_are':'working'}

· proxite = {

·     'http':'http://127.0.0.1:8080',

·     'https':'https://127.0.0.1:8080'

· }

· res = requests.get(url, cookies=cookies, proxite=proxite, verify=False

· )

#verify=False  在请求的时候把verify参数设置为False就可以关闭证书验证了


另外在header内添加些其他能用到的字段,可以达到自己编辑http响应头的目的,代码片段如下。


headers = {

'Proxy-Connection': 'keep-alive',

'Upgrade-Insecure-Requests': '1',

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',

'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',

'Accept-Encoding': 'gzip, deflate',

'Accept-Language': 'zh-CN,zh;q=0.9'

    }

不同页面HTML的获取条件是不一样的。对此,我们在使用的时候需要根据实际情况进行编写,一般情况下添加UA即可。如果我们的目标是一个网站登录后的页面,为了能爬取到HTML,我们还需要用到cookie字段,如图6所示,或者表单模拟用户登录。


QmwUvs7e_mkSR.png


#表单模拟用户登录

import requests

from fake_useragent import UserAgent

#生成随机UA

url = 'https://*****.com/login'

headers = {

    'User-agent' : UserAgent().random,

}

data = {

    'name' : '你的',

    'password' : '你的'

}

response = requests.post(url,headers=headers,data=data)

response.encoding = 'utf-8'

print(response.text)


其他字段对于一般爬虫而言不一定有用,但笔者也将它们列举出来,希望可以为读者拓宽思路。


3数据提取


XPath

XPath即XML路径语言(XML Path Language),它是一种用来确定xml文档中某部分位置的语言。


xml文档(html属于xml)是由一系列节点构成的树,例如:


<html>

<body>

<div >

<p>Hello world<p>

<a href="/home">Click here</a>

</div>

</body>

</html>


xml文档的节点有多种类型,其中最常用的有以下几种:

  • 根节点整个文档树的根。

  • 元素节点 html、body、div、p、a。

  • 属性节点 href。

  • 文本节点 Hello world、Click here。


节点间的关系有以下几种:

  • 父子 body是html的子节点,p和a是div的子节点。反过来,div是p和a的父节点。

  • 兄弟 p和a为兄弟节点。

  • 祖先/后裔 body、div、p、a都是html的后裔节点;反过来html是body、div、p、a的祖先节点。


XPath常用的基本语法如图7所示。


0AcPYkqwq_FVOK.png


下面,我们看看XPath的3个常用函数的使用。

String(arg):返回参数的字符串

Contains(str1,str2):判断str1中是否包含str2,返回布尔值

Text():提取文本


举下面这个例子说明:

<div class="c-span9 c-span-last"><div><span class=" newTimeFactor_before_abs c-color-gray2 m">2020年6月19日 </span></div><style>.user-avatar {

}</style><div class="f13 c-gap-top-xsmall se_st_footer user-avatar"><a target="_blank" href="http://www.baidu.com/;" style="text-decoration:none;position:relative;"><div class="c-img c-img-circle c-gap-right-xsmall" style="display: inline-block;width: 16px;height: 16px;position: relative;top: 3px;vertical-align:top;"><img src=""></div>知乎</a><div class="c-tools c-gap-left" id="tools_4828209406812473379_2" data-tools="{"title":"通俗的讲,网络爬虫到底是什么? - 知乎","url":"http://www.baidu.com/link?url=7rZRcme-wDX4h3VV5_YIsgYiQ9k-Vno9y5n5VMA9uSZT9_bMdDBN9RdvSMVyQsPWu91QvJbSz5Zsa6mngIvqj_"}"><i class="c-icon f13"></i></div><span><span></span></span><style>.snapshoot, .snapshoot:visited {

        color: #9195A3!important;

    }

    .snapshoot:active, .snapshoot:hover {

        color: #626675!important;

    }</style><a data-click="{'rsv_snapshot':'1'}" href="http://cache.baiducontent.com" target="_blank" class="m c-gap-left c-color-gray kuaizhao snapshoot">百度快照</a></div></div>

例如这个html代码,假设我需要提取的是百度快照四个字。就可以构造如下的XPath。


//div[@class="c-row c-gap-top-small"]/div/div/a[2]


可以看到效果如图8所示。

fMheaCNK_JbpS.png


CSS选择器


CSS选择器的语法比XPath更简单一些,但功能不如XPath强大。实际上,当我们调用Selector对象的CSS方法时,在其内部会使用Python库cssselect将CSS选择器表达式翻译成XPath表达式,然后调用Selector对象的XPATH方法。CSS选择器的常用的基本语法如图9所示。


0wWeTyBhs_NxHH.png


CSS选择器的例程如下所示。

print(soup.select('a[href="http://example.com/elsie"]'))  # 寻找a标签中href="http://example.com/elsie"的标签
print(soup.select('a[href^="http://example.com/"]'))  # 寻找href属性值是以"http://example.com/"开头的a标签
print(soup.select('a[href$="tillie"]'))#寻找href属性值是以tillie为结尾的a标签
print(soup.select('a[href*=".com/el"]'))#寻找href属性值中存在字符串”.com/el”的标签a


其中,网页http://example.com/elsie的内容如下。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>hjk</title>
</head>

<body>
<p name="dromouse"><b>The Dormouse's story</b></p>
<p>Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" title="12" id="link1"><!-- Elsie --></a>,
    <a href="http://example.com/lacie" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
<p>...</p>
</body>
</html>


输出结果如下。

[<a href="http://example.com/elsie" id="link1" title="12"><!-- Elsie --></a>]
[<a href="http://example.com/elsie" id="link1" title="12"><!-- Elsie --></a>, <a href="http://example.com/lacie" id="link2">Lacie</a>, <a href="http://example.com/tillie" id="link3">Tillie</a>]
[<a href="http://example.com/tillie" id="link3">Tillie</a>]
[<a href="http://example.com/elsie" id="link1" title="12"><!-- Elsie --></a>]


正则数据提取

正则表达式是一种文本模式,包括普通字符和特殊字符。正则表达式使用单个字符串来描述、匹配一系列某个句法规则的字符串。


虽然繁琐,但正则表达式同时也是强大的,学会应用之后可以提高效率。许多程序设计语言都支持利用正则表达式进行字符串操作。


常用的正则表达式如表2所示。

表2

用户名

/^[a-z0-9_-]{3,16}$/

密码

/^[a-z0-9_-]{6,18}$/

十六进制值

/^#?([a-f0-9]{6}|[a-f0-9]{3})$/

电子邮箱

/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
/^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/

URL

/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/

IP 地址

/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

HTML 标签

/^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/

删除代码\\注释

(?<!http:|\S)//.*$

Unicode编码中的汉字范围

/^[\u2E80-\u9FFF]+$/


由于正则表达式比较晦涩,难以记忆,所以在更多的情况下进行爬虫时使用的是xpath、css选择器。在编写爬虫时,并无规定章法(习惯什么用什么,想用什么用什么,能用什么用什么)。


下面举两个数据提取的整合方式如下:


案例1:由xpath提取该标签下的文本内容,通过正则提取价格的数字部分 ['99.00', '88.00', '80.00']


selector = response.css('ul.pager li.next a::attr(href)').extract()

#通过css选取目标范围

 selector.xpath('.//li/b/text()').re('\d+\.\d+')


案例2:#套路于上一个例子是一样的,通过字典的形式进行数据封装,正则数据过滤在封装数据时一同进行。

selector = response.css('ul.pager li.next a::attr(href)').extract()

#通过css选取目标范围

 selector.xpath('.//li/b/text()').re('\d+\.\d+')

#由xpath提取该标签下的文本内容,通过正则提取价格的数字部分 ['99.00', '88.00', '80.00']

#举例如下:

def get_infos(html):

    html = etree.HTML(html)

    infos = response.css('ul.pager li.next a::attr(href)').extract()

    for info in infos:

        exp_name = info.xpath('./a/text()')[0]

        url_info = info.xpath('./a/@href')[0]

        time_day = info.xpath('./span[@class="y-right"]/text()')[0]

        data = {

            '漏洞名称': exp_name.replace('\n', '').replace(' ', '').re('\d+\.\d+'),

            '漏洞地址': 'https://help.xxxx.com{}'.format(url_info),

            '日期': time_day.re('\d+\.\d+'),

            #'时间': time,

        }

        print(data)

        print('\n')


JSON数据提取


JSON是一种轻量级的数据交换格式。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。在易于人阅读和编写的同时,JSON也易于机器解析和生成,并能有效地提升网络传输效率。


一般在爬取动态页面时才会使用到JSON提取数据。


我们以https://www.cnbeta.com/为例,爬取页面的内容,如图10、11所示:


7ZYvSRx8_H7kM.png


gEJtI6Sx_ryTE.png


这是一个动态页面,动态页面通过json进行传输数据,所以我们对动态页面的爬取就是对动态页面的js的提取。该网站不仅对referer和UA进行了校验,同时还在页面中通过JavaScript语句进行动态链接请求,从而导致不能动态获取页面中的信息,所以只是展示一个jsonpath提取json数据的小栗子,代码示例如下。


#下面据一个提取json数据的小例子

Import jsonpath

def get_infos(html):

    html = json.loads(html)

    list_html = jsonpath.jsonpath(html,'$..data_list')

    for infos in list_html:

        for info in infos:

            title=[jsonpath.jsonpath(info,'$..post_title')]

            title = str(title)

            title=title[3:-3]

            first_url=jsonpath.jsonpath(info,'$..url')

            first_url = str(first_url)

            first_url=first_url[2:-3]

            time=jsonpath.jsonpath(info,'$..post_date')

            first_content=jsonpath.jsonpath(info,'$..content')

            data = {

                    '安全讯息': title,

                    '讯息地址': 'https://s.tencent.com{}'.format(first_url),

                    '日期': time,

                    '内容简介': first_content,

                }

            print(data)

            print('\n')


4IP代理


大家可能都有过给浏览器设置HTTP代理的经验,HTTP代理服务器可以比作客户端与Web服务器(网站)之间的一个信息中转站,客户端发送的HTTP请求和Web服务器返回的HTTP响应通过代理服务器转发给对方,如图12所示:

0C6xMcYXm_tDIP.png



爬虫程序在爬取某些网站时也需要使用代理,常见原因可包括:

  • 由于网络环境因素,直接爬取速度太慢,使用代理可提高爬取速度。

  • 某些网站对用户的访问速度进行限制,爬取过快会被封禁 ip,使用代理的话可以防止被封禁。

  • 由于地方法律或政治原因,某些网站无法直接访问,使用代理则可以绕过访问限制。


通过python查看IP的代码如下所示:


import requests

headers = {

    'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'

}

url = 'http://icanhazip.com/'

response = requests.get(url,headers=headers)

ip = response.text.replace('\n','')

print(ip)

想要更换IP,就需要使用到大量的IP。


首先付费版代理IP有如:


免费版代理IP有如:


编写爬虫爬取上面的IP、端口信息的结果如图13所示:

GJjSLFJP_GM8s.png


IP代理使用如下的代码示例如下:


import requests

# 代理服务器

proxyHost = "http-dyn.abuyun.com"

proxyPort = "9020"

# 代理隧道验证信息

proxyUser = ''

proxyPass = ''

proxyMeta = "http://%(user)s:%(pass)s@%(host)s:%(port)s" % {

    "host": proxyHost,

    "port": proxyPort,

    "user": proxyUser,

    "pass": proxyPass,

}

#可以读取文件批量便利

proxies = {

    "http": proxyMeta,

    "https": proxyMeta,

}

headers = {

    'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'

}

url = 'http://icanhazip.com/'

response = requests.get(url,headers=headers,proxies=proxies)

ip = response.text.replace('\n','')

print(“成功获取到代理”,ip)


上述代码也可以用来检测爬取到的代理能否正常使用。


5API接口调用


API 中文名叫【编程应用接口】,换句话说,这是一种接口,在爬虫中也被广泛使用。


爬虫是通过访问其他网站,然后从中提取结构化的数据,进行抓包分析,正则,bs4 ,js 逆向等等,整体比较麻烦。相比之下,API接口的调用就会方便得多。如果对方开放了 API 接口,则可以考虑使用接口,这可达到事半功倍的效果,因为对方如果有 API接口,说明对方有对外开放数据,那我们获得数据也就方便,只需要请求接口,得到返回的 json 数据即可,不用担心反爬。


大家常听到的 API 类型,应该是【天气预报API】,【百度地图API】之类的,现在有很多 API 服务,我们可以根据需求寻找对应的。


若遇到了Ajax动态加载的情况怎么办?这和前面通过json提取动态页面是一样的。


https://gank.io/api

zcwrFIq9_mbpO.png


可以看到调用api接口后,得到一个json数据,所以这里我们可以使用上文提到的json数据提取方法进行数据的提取。


6法律法规


网络运营者采取自动化手段访问收集网站数据,不得妨碍网站正常运行;此类行为严重影响网站运行,如自动化访问收集流量超过网站日均流量三分之一,网站要求停止自动化访问收集时,应当停止。


以下是司法解释里面提到以下集中类型的数据,无论是“非法提供”和“非法获取”都可以入刑


第一类:高度敏感信息,包括四种信息:行踪轨迹信息、通信内容、征信信息、财产信息。涉及高度敏感信息的违法活动,由于定罪门槛最低,因此严格限制在此四类,不做任何扩展;


第二类:敏感信息,即住宿信息、通信记录、健康生理信息、交易信息等其他可能影响人身、财产安全的公民个人信息。与第一类相比较,《解释》对第二类信息的界定仍留有空间,意味着在司法实践中,仍有可能会出现目前所列举之外的第二类信息类型;


第三类:其他个人信息。即上述第二、三类以外的个人信息。个人信息的类型是定罪量刑的重要依据。越敏感信息,达到定罪门槛的信息数量越少


本文作者:安全狗

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/157549.html

Tags:
评论  (0)
快来写下你的想法吧!

安全狗

文章数:17 积分: 165

基于智能驱动的新一代云安全公司

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号