爬虫基本介绍

什么是爬虫

1.爬虫简介

  近年来,随着网络应用的逐渐扩展和深入,如何高效的获取网上数据成为了无数公司和个人的追求,在大数据时代,
谁掌握了更多的数据,谁就可以获得更高的利益,而网络爬虫是其中最为常用的一种从网上爬取数据的手段。

  网络爬虫,即Web Spider,是一个很形象的名字。如果把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。
网络蜘蛛是通过网页的链接地址来寻找网页的。网站某一个页面(通常是首页)开始,读取网页的内容,
找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。
如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。

爬虫前置知识点:

#1、什么是互联网?
    互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,像一张网一样。

#2、互联网建立的目的?
    互联网的核心价值在于数据的共享/传递:数据是存放于一台台计算机上的,而将计算机互联到一起的目的就是为了能够方便彼此之间的数据共享/传递,否则你只能拿U盘去别人的计算机上拷贝数据了。

#3、什么是上网?爬虫要做的是什么?
    我们所谓的上网便是由用户端计算机发送请求给目标计算机,将目标计算机的数据下载到本地的过程。
    #3.1 只不过,用户获取网络数据的方式是:
      浏览器提交请求->下载网页代码->解析/渲染成页面。

    #3.2 而爬虫程序要做的就是:
      模拟浏览器发送请求->下载网页代码->只提取有用的数据->存放于数据库或文件中
 
    #3.1与3.2的区别在于:
      我们的爬虫程序只提取网页代码中对我们有用的数据

#4、总结爬虫
    #4.1 爬虫的比喻:
      如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的猎物/数据

    #4.2 爬虫的定义:
      向网站发起请求,获取资源后分析并提取有用数据的程序 

    #4.3 爬虫的价值:
      互联网中最有价值的便是数据,比如天猫商城的商品信息,链家网的租房信息,雪球网的证券投资信息等等,这些数据都代表了各个行业的真金白银,可以说,谁掌握了行业内的第一手数据,谁就成了整个行业的主宰,如果把整个互联网的数据比喻为一座宝藏,那我们的爬虫课程就是来教大家如何来高效地挖掘这些宝藏,掌握了爬虫技能,你就成了所有互联网信息公司幕后的老板,换言之,它们都在免费为你提供有价值的数据。

2. 哪些语言可以实现爬虫

# 1.php:
    可以实现爬虫。php被号称是全世界最优美的语言(当然是其自己号称的,就是王婆卖瓜的意思),但是php在实现爬虫中支持多线程和多进程方面做的不好。

# 2.java:
    可以实现爬虫。java可以非常好的处理和实现爬虫,是唯一可以与python并驾齐驱且是python的头号劲敌。但是java实现爬虫代码较为臃肿,重构成本较大。

# 3.c、c++:
    可以实现爬虫。但是使用这种方式实现爬虫纯粹是是某些人(大佬们)能力的体现,却不是明智和合理的选择。

# 4.python:
    可以实现爬虫。python实现和处理爬虫语法简单,代码优美,支持的模块繁多,学习成本低,具有非常强大的框架(scrapy等)且一句难以言表的好!没有但是!

3.爬虫的应用

# 1.通用爬虫:通用爬虫是搜索引擎(Baidu、Google、Yahoo等)“抓取系统”的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
  1)搜索引擎如何抓取互联网上的网站数据?
     a)门户网站主动向搜索引擎公司提供其网站的url
     b)搜索引擎公司与DNS服务商合作,获取网站的url
     c)门户网站主动挂靠在一些知名网站的友情链接中

# 2.聚焦爬虫:聚焦爬虫是根据指定的需求抓取网络上指定的数据。
  例如:
      获取豆瓣上电影的名称和影评,而不是获取整张页面中所有的数据值。

爬虫的基本流程

 

#1、发起请求
使用http库向目标站点发起请求,即发送一个Request
Request包含:请求头、请求体等

#2、获取响应内容
如果服务器能正常响应,则会得到一个Response
Response包含:html,json,图片,视频等

#3、解析内容
解析html数据:正则表达式,第三方解析库如Beautifulsoup,pyquery等
解析json数据:json模块
解析二进制数据:以b的方式写入文件

#4、保存数据
数据库

请求与响应

'''
URL:
    即统一资源定位符,也就是我们说的网址,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
    互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

URL的格式由三部分组成:
    ①第一部分是协议(或称为服务方式)。
    ②第二部分是存有该资源的主机IP地址(有时也包括端口号)。
    ③第三部分是主机资源的具体地址,如目录和文件名等

http协议:
    https://www.cnblogs.com/Yang-Sen/p/9076804.html

robots协议: 
    https://www.cnblogs.com/kermitjam/articles/9692568.html

Request:
    用户将自己的信息通过浏览器(socket client)发送给服务器(socket server)

Response:
    服务器接收请求,分析用户发来的请求信息,然后返回数据(返回的数据中可能包含其他链接,如:图片,js,css等)

ps:
  浏览器在接收Response后,会解析其内容来显示给用户,而爬虫程序在模拟浏览器发送请求然后接收Response后,是要提取其中的有用数据。
'''

Request

#1、请求方式:
    常用的请求方式:GET,POST
    其他请求方式:HEAD,PUT,DELETE,OPTHONS

    ps:用浏览器演示get与post的区别,(用登录演示post)

    post与get请求最终都会拼接成这种形式:k1=xxx&k2=yyy&k3=zzz
    post请求的参数放在请求体内:
        可用浏览器查看,存放于form data内
    get请求的参数直接放在url后

#2、请求url
    url全称统一资源定位符,如一个网页文档,一张图片
    一个视频等都可以用url唯一来确定

    url编码
    https://www.baidu.com/s?wd=图片
    图片会被编码(看示例代码)


    网页的加载过程是:
    加载一个网页,通常都是先加载document文档,
    在解析document文档的时候,遇到链接,则针对超链接发起下载图片的请求

#3、请求头
    User-agent:请求头中如果没有user-agent客户端配置,
    服务端可能将你当做一个非法用户
    host
    cookies:cookie用来保存登录信息

    一般做爬虫都会加上请求头


#4、请求体
    如果是get方式,请求体没有内容
    如果是post方式,请求体是format data

    ps:
    1、登录窗口,文件上传等,信息都会被附加到请求体内
    2、登录,输入错误的用户名密码,然后提交,就可以看到post,正确登录后页面通常会跳转,无法捕捉到post 

 

Cookie

```
Cookie: "......"
同样是一个比较关键的字段,Cookie是 client 请求 服务器时,服务器会返回一个键值对样的数据给浏览器,下一次浏览器再访问这个域名下的网页时,就需要携带这些键值对数据在 Cookie中,用来跟踪浏览器用户的访问前后路径。 
在爬虫时,我会根据前次访问得到 cookie数据,然后添加到下一次的访问请求头中。
```

- User-Agent

```
中文名用户代理,服务器从此处知道客户端的 操作系统类型和版本,电脑CPU类型,浏览器种类版本,浏览器渲染引擎,等等。这是爬虫当中最最重要的一个请求头参数,所以一定要伪造,甚至多个。如果不进行伪造,而直接使用各种爬虫框架中自定义的user-agent,很容易被封禁。举例:
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
网上有很多的用户代理大全,用户代理大全越多越好,用以伪造多个请求头。
```
- Referer
```
浏览器上次访问的网页url,uri。由于http协议的无记忆性,服务器可从这里了解到客户端访问的前后路径,并做一些判断,如果后一次访问的 url 不能从前一次访问的页面上跳转获得,在一定程度上说明了请求头有可能伪造。 
我在爬虫时,起始入口我会给一个随意的百度搜索地址,然后,在爬取过程中,不断将索引页面的url添加在伪造请求头中。
Referer: https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3&rsv_spt=1&rsv_iqid=0xce19ceff0002f196&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=1&oq=%25E7%25BE%258E%25E5%25A5%25B3&inputT=4&rsv_t=46216vF7O9LH18hEfGKnjaFukwpJdM3UIwrvEb6LkFIXOIsDt2OQf5Ocfy%2F5LJsCTnkJ&rsv_sug3=9&rsv_sug1=6&rsv_sug7=100&rsv_sug2=0&rsv_pq=e4b29f73000184eb&rsv_sug4=596&rsv_sug=1
```

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

指定客户端可以接受的内容类型,比如文本,图片,应用等等,内容的先后排序表示客户端接收的先后次序,每种类型之间用逗号隔开。 
其中,对于每一种内容类型,分号 ; 后面会加一个 q=0.6 这样的 q 值,表示该种类型被客户端喜欢接受的程度,如果没有表示 q=1,数值越高,客户端越喜欢这种类型。 
爬虫的时候,我一般会伪造若干,将想要找的文字,图片放在前面,其他的放在后面,最后一定加上*/*;q=0.8。

比如Accept: image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*

text/xml,text/shtml:文本类型,斜杠后表示文档的类型,xml,或者shtml
application/xml,application/xhtml+xml:应用类型,后面表示文档类型,比如 flash动画,excel表格等等
image/gif,image/x-xbitmap:图片类型,表示接收何种类型的图片
```

- Accept-Language
```
客户端可以接受的语言类型,参数值规范和 accept的很像。一般就接收中文和英文,有其他语言需求自行添加。比如:

Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
zh-CN:中文简体大陆?
zh:其他中文
en-US:英语美语
en:其他英语

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

- Accept-Encoding: 
```
客户端接收编码类型,一些网络压缩格式。我看了很多常见的请求头,基本上都不变,就是如下:

Accept-Encoding: gzip, deflate, sdch。相对来说,deflate是一种过时的压缩格式,现在常用的是gzip
```
- Cache-Control
```
Cache-Control: no-cache
指定了服务器和客户端在交互时遵循的缓存机制,即是否要留下缓存页面数据。 
一般在使用浏览器访问时,都会在计算机本地留下缓存页面,相当于是浏览器中的页面保存和下载选项。但是爬虫就是为了从网络上爬取数据,所以几乎不会从缓存中读取数据。所以在设置的时候要侧重从服务器请求数据而非加载缓存。

no-cache:客户端告诉服务器,自己不要读取缓存,要向服务器发起请求
no-store:同时也是响应头的参数,请求和响应都禁止缓存,即不存储
max-age=0:表示当访问过此网页后的多少秒内再次访问,只加载缓存,而不去服务器请求,在爬虫时一般就写0秒
一般爬虫就使用以上几个参数,其他的参数都是接受缓存的,所以就不列出了。

```

- Connection
```
Connection: keep-alive
请求头的 header字段指的是当 client 浏览器和 server 通信时对于长链接如何处理。由于http请求是无记忆性的,长连接指的是在 client 和server 之间建立一个通道,方便两者之间进行多次数据传输,而不用来回传输数据。有 close,keep-alive 等几种赋值,close表示不想建立长连接在操作完成后关闭链接,而keep-alive 表示希望保持畅通来回传输数据。

此外,connection还可以存放一些自定义声明,比如:

Connection: my-header, close
My-Header: xxx
其中,my-header指的是当前访问请求中使用的请求头,close表示数据传输完毕后不保持畅通,关闭链接。

在爬虫时我一般都建立一个长链接。
```


- Host
```
Host:www.baidu.com
访问的服务器主机名,比如百度的 www.baidu.com。这个值在爬虫时可以从 访问的 URI 中获得
```

- Pragma
```
Pragma: no-cache
和 cache-control类似的一个字段,但是具体什么含义我还没有查清楚,一般爬虫时我都写成 no-cache。
```

- Proxy-Connection
```
当使用代理服务器的时候,这个就指明了代理服务器是否使用长链接。但是,数据在从client 到代理服务器,和从代理服务器到被请求的服务器之间如果存在信息差异的话,会造成信息请求不到,但是在大多数情况下,都还是能够成立的。
```

- Accept-Charset
```
指的是规定好服务器处理表单数据所接受的字符集,也就是说,客户端浏览器告诉服务器自己的表单数据的字符集类型,用以正确接收。若没有定义,则默认值为“unknown”。如果服务器没有包含此种字符集,就无法正确接收。一般情况下,在爬虫时我不定义该属性,如果定义,例子如下:
Accept-Charset:gb2312,gbk;q=0.7,utf-8;q=0.7,*;q=0.7
```

- Upgrade-Insecure-Requests
```
自动将不安全的访问请求转换成安全的请求 request。赋值数字1表示可以,0就表示不可以。
```
- Range
```
浏览器告诉 WEB 服务器自己想取对象的哪部分。这个在爬虫时我接触比较少,一般都是爬取整个页面,然后再做分析处理。
```
- If-Modified-Since
```
只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304。其目的是为了提高访问效率。但是在爬虫时,不设置这个值,而在增量爬取时才设置一个这样的值,用以更新信息。
```
请求头参数

 

import requests
from urllib.parse import urlencode


headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Cookie': 'BIDUPSID=129BFA4FF0032F16FF1851332ADFC9E1; PSTM=1521466015; BD_UPN=12314753; MCITY=-154%3A; '
              'BAIDUID=8E87475C1F615023B288E8FEF225AE72:FG=1; '
              'BDUSS=i1SVmoyV2thVFpqMFY4RlpzYmgtQUdJdFI0aW5mY1BnenRGaW5mTmZzNDdzfnRjSVFBQUFBJCQAAAAAAAAAAAEAAADZOm5rYTE1NzM4Mjc4NTgyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADsm1Fw7JtRcV;'
              ' BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; ispeed_lsm=2; delPer=0; BD_CK_SAM=1; BD_HOME=1; H_PS_PSSID=1453_28939_21109_28518_28773_28723_28963_28830_28584; '
              'PSINO=7; COOKIE_SESSION=1647_0_6_6_14_5_0_0_6_2_422_0_0_0_427_0_1557927845_0_1557929065%7C9%230_0_1557929065%7C1; ZD_ENTRY=baidu; sugstore=1',
    'Host': 'www.baidu.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36'
}

# data = requests.get('https://www.baidu.com', headers=headers)

data1 = requests.get('https://www.baidu.com/s?' + urlencode({'wd':'美女'}), headers=headers)

print(data1.text)
View Code

Response

#1、响应状态
    200:代表成功
    301:代表跳转
    404:文件不存在
    403:权限
    502:服务器错误

#2、Respone header
    set-cookie:可能有多个,是来告诉浏览器,把cookie保存下来
    
#3、preview就是网页源代码
    最主要的部分,包含了请求资源的内容
    如网页html,图片
    二进制数据等

总结

#1、总结爬虫流程:
    爬取--->解析--->存储

#2、爬虫所需工具:
    请求库:requests,selenium
    解析库:正则,beautifulsoup,pyquery
    存储库:文件,MySQL,Mongodb,Redis

#3、爬虫常用框架:
    scrapy

 

import bs4
import requests
from bs4 import BeautifulSoup


# 通过传入网址信息创建一个获取网页文本的函数
def getHTMLText(url):
    # 判断获取网页文本过程中是否有错误
    try:
        # 打开网址获取文本,并且把延迟设置成30s
        r = requests.get(url, timeout=30)
        # 获取状态码
        r.raise_for_status()
        # 设置文件编码
        r.encoding = r.apparent_encoding
        # 如果成功返回网页文本
        return r.text
    except:
        # 获取网页文本有错误则返回空文本
        return ""


# 通过传入空列表和网页文本信息创建一个在大学列表中加入大学信息的函数
def fillUnivList(ulist, html):
    # 用BeautifulSoup将网页文本以’html.parser‘煮成一锅粥
    soup = BeautifulSoup(html, "html.parser")
    # 通过网页源代码我们可以发现我们需要的信息都在tbody标签内,因此我们循环找出’tbody‘标签及其子标签的内容
    for tr in soup.find('tbody').children:
        # 通过bs4.element.Tag判断是否为tr标签
        if isinstance(tr, bs4.element.Tag):
            # 对于tr标签的我们拿到tr标签里的td标签
            tds = tr('td')
            # [<td>1</td>, <td><div align="left">清华大学</div></td>, <td>北京</td>, <td>95.3</td>...
            # 我们通过筛选出我们需要的td标签中的文本并将其用列表的方式加入我们传入的列表ulist中
            ulist.append([tds[0].string, tds[1].string,
                          tds[2].string, tds[3].string])


# 通过传入学校列表信息创建一个打印大学列表的函数
def printUnivList(ulist,province):
    # 打印标题
    print("中国最好大学排名2019({}地区)".center(45, '-').format(province))
    # 设置一个format格式化的模板
    # 注意:这里的{4}是因为utf8格式的英文和中文字节数不同,python会自动用英文来填
    tplt = "{0:^10}\t{1:{4}^10}\t{2:^10}\t{3:^10}"
    # 充空白位置,我们用chr(12288)将其修改成用中文填充空白位置
    # 打印第一行
    print(tplt.format("排名", "学校名称", "地区", "总分", chr(12288)))
    if province == '浙江':
        print(tplt.format(1, '宁波财经学院', '浙江', 99.9, chr(12288)))
    # 循环取出列表中的每一所大学的信息,取出的大学信息是列表的形式(可以控制range(len(ulist))的长度来控制想要打印的学校的数量)
    for i in range(len(ulist)):
        # 将每一所大学的信息以列表的形式赋值给u
        u = ulist[i]
        # u[2]是地区,判断是否为安徽地区(可以自己更改地区信息,如果删除该判断,打印所有学校信息,也可以更改判断条件)
        if u[2] == province:
            # 如果为安徽地区,我们打印属于安徽地区的每一所大学的信息
            print(tplt.format(u[0], u[1], u[2], u[3], chr(12288)))


# 创建一个运行函数
def main(province='安徽'):
    # 创建一个空列表,为填充大学信息列表做准备
    uinfo = []
    # 定义一个想要爬取的网页
    url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2019.html'
    # 传入想要爬取的网页获取该网页文本信息
    html = getHTMLText(url)
    # 给填充大学信息函数传值
    fillUnivList(uinfo, html)
    # 给打印大学信息函数传值
    printUnivList(uinfo,province=province)


main(province='浙江')
# main(province='北京')
View Code

 

posted @ 2019-05-16 09:56  Sean_Yang  阅读(1251)  评论(0编辑  收藏  举报