1.爬虫是什么?

引言:爬虫?什么是爬虫?
爬虫的定义:模拟浏览器发送请求,获取响应。

书面化爬虫简介!!!点我哦!!!

  1. 爬虫的作用:
    1.数据采集
        抓取微博评论(机器学习舆情监控)
        抓取招聘网站的招聘信息(数据分析,挖掘)
        新浪滚动新闻
        百度新闻网站
    2.软件测试
        爬虫之自动化测试
        虫师
    3.12306抢票
    4.网站上的投票
    5.网络安全
        短信轰炸
        web漏洞扫描
  1. 爬虫的分类:
根据被爬取的数量不同,分类:
    通用爬虫:通常指搜索引擎的爬虫       具有很大的局限性:大部分内容没有用,不同搜索目的,返回的内容相同!
	(通用爬虫是搜索引擎抓取系统 (baidu,goole,yahoo等)的重要组成部分 。
	主要目的是将互联网的网页下载到本地 ,形成一个互联网内容的镜像备份。)
	
    聚焦爬虫:针对特定网站的爬虫
    (是面向特定主题需求的一种网络爬虫程序 ,它与通用搜索引擎爬虫的区别在于 :
	聚焦爬虫在实施页面抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息)
    
根据是否获取数据为目的,分类:
    功能性爬虫,比如,投票,点赞
    数据增量爬虫,比如招聘信息
    
根据url地址和对应的页面内容是否改变,数据增量爬虫分类:
    基于url地址变化,内容也随之变化的数据增量爬虫
    url地址不变,内容变化的数据增量爬虫
  1. 工作流程:
流程:url——>发送请求,获取响应——>提取数据——>保存数据
    发送请求,获取响应——>提取url地址,继续请求

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. robots协议:
    robots协议:网站通过robots协议,告诉我们搜索引擎哪些页面可以抓取,哪些页面不能抓取,但它仅仅是道德层面上的约束。

  2. http的重点请求头:

http的重点请求头:
    user-agent:告诉对方服务器是什么客户端正在请求资源,爬虫中模拟浏览器非常重要的一个手段
    爬虫中通过把user-agent设置为浏览器的ua,能够达到模拟浏览器的效果。
    cookie:获取登录之后,才能够访问的资源
    
常见的请求头,响应头
    Content-Type
    Host(主机和端口号)
    Upgrade-Insecure-Rwquests(升级为https请求)
    User-Agent(浏览器名称)
    Referer(页面跳转处)
    Cookie
    Authorization(用于表示http协议中需要认证资源的认证信息,如jwt认证)
    
  1. 浏览器发送http请求的过程:
浏览器发送http请求的过程:
1.域名解析 --> 

2.发起TCP的3次握手 --> 

3.建立TCP连接后发起http请求 --> 

4.服务器响应http请求,浏览器得到html代码 --> 

5.浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 

6.浏览器对页面进行渲染呈现给用户.


注意:
在网页的检查里的Network->Name->Request Headers  view parsed下
的Connection:keep-alive保持常连接,就不用频繁的三次握手和三次分手!
浏览器获取的内容(elements的内容)包含:url地址对应的响应+js+css+jpg
爬虫会获取:url地址对应的响应
爬虫获取的内容和elements内容不一样,进行数据提取的时候,需要根据url地址对应的响应为准
  1. http和HTTPS的概念:
		1.http超文本传输协议      协议默认端口80
		2.https也是超文本传输协议  协议默认端口443
		http因为是明文传输,而https是密文传输,所以HTTPS比http更安全,但是性能低,因为解密需要消耗时间!
2.正式进入爬虫—requests模块的使用!

在这里插入图片描述

1.url地址解码的方法:
requests.utils.unquote(url)

2.requests中headers如何使用:
    headers = {"User-Agent":""}
    requests.get(url,headers=headers)

3.requests中如何发送post请求:
    data = {"浏览器中的form data"}
    requests.post(url,data=data)

概念:爬虫就是模拟浏览器发送网络请求,获取请求响应

4.requests如何发送请求和获取响应:
    response = requests.get(url)
    
    response.text ---> str(获取的数据是字符串类型)
    response.encoding="utf-8"(乱码需要解码,修改编码方式)
    
    response.content ---> bytes(获取的数据是字节类型)
    response.content.decode()(字节需要编码)

5.响应:
response.text                          str类型,
response.content                       获取内容,字节类型,需要decode编码
response.status_code                   获取状态码
response.request.headers               响应对应的请求头
response.headers                       响应头
response.request.url                   请求url地址
response.url                           响应url地址
response.request._cookie               响应对应请求的cookie;返回cookiejar类型
response.cookies			           响应cookie(经过了set-cookie动作,返回cookiejar类型)
response.json()			               自动将json字符串类型的响应内容转换为python对象(dict  或者  list6.发送带参数的请求:
params = {"":""}
url_temp = "不完整的URL地址"
requests.get(url_temp,params=params)
例:wd为百度词条搜索url的参数key值

在这里插入图片描述

3.实战:利用requests库进行百度贴吧的爬取!
import os
import requests

'''
为了构造正确的url!!!
进入百度贴吧进行测试,任意搜索一个信息,通过不同页更换,观察url找寻规律:
https://tieba.baidu.com/f?kw=美食&ie=utf-8&pn=0
https://tieba.baidu.com/f?kw=美食&ie=utf-8&pn=50
https://tieba.baidu.com/f?kw=美食&ie=utf-8&pn=100
https://tieba.baidu.com/f?kw=美食&ie=utf-8&pn=150
'''

class TiebaSpider:
    def __init__(self,tieba_name):
        self.tieba_name = tieba_name
        self.url_temp = "https://tieba.baidu.com/f?kw="+tieba_name+"&ie=utf-8&pn={}"
        self.headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"}

    # 构造url列表
    def get_url_list(self):
        return [self.url_temp.format(i*50) for i in range(5)]

    # 发送请求,获取响应
    def parse_url(self,url):
        response = requests.get(url,headers=self.headers)
        return response.content.decode()

    # 保存
    def save_html_str(self, html_str, page_num):
        file_path = "{}_第{}页.html".format(self.tieba_name, page_num)
        dir = 'ceshi'
        if not os.path.exists(dir):
            os.mkdir(dir)
        file_path = dir + '/' + file_path
        with open(file_path, "w", encoding='utf-8') as f:
            f.write(html_str)
        print("保存成功!")

    # 实现主要逻辑
    def run(self):
        # 构造url列表
        url_list = self.get_url_list()
        # 发送请求,获取响应
        for url in url_list:
            html_str = self.parse_url(url)
            # 保存
            page_num = url_list.index(url)+1
            self.save_html_str(html_str, page_num)

if __name__ == '__main__':
    name_date = input("请输入你想知道的内容:")
    tieba_spider = TiebaSpider(name_date)
    tieba_spider.run()

本代码是爬取指定搜索内容获取到的html源码头5页!

在这里插入图片描述

4.requests模块发送post请求

应用场景:登录注册
需要传输大文本内容的时候(post请求对长度没有要求)

  1. 用法:
    response = requests.post(“http://www.baidu.com”, data = data, headers = headers)
    data的形式:字典
    data的来源:固定值,抓包(form data)

实战:汉译英爬虫实现!

import requests
import json
class King(object):
    def __init__(self, word):
        self.url = 'http://fy.iciba.com/ajax.php?a=fy'
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'}
        self.data = {
            'f': 'auto',
            't': 'auto',
            # 'w': '字典'
            'w': word
        }
    def post_data(self):
        response = requests.post(self.url, data=self.data, headers=self.headers)
        return response.content

    def parse_data(self,data):
        # 将json字符串转化为字典
        dict_data = json.loads(data)
        try:
            print(dict_data['content']['out'])
        except:
            print(dict_data['content']['word_mean'][0])

    def run(self):
        # 编写爬虫的逻辑
        # url
        # headers
        # data 字典
        # 发送请求获取响应
        response = self.post_data()
        # print(response)
        # 数据分析
        # 获取翻译后的结果
        self.parse_data(response)

if __name__ == '__main__':
    word = input('请输入要翻译的单词或者句子:')
    king = King(word)
    king.run()

在这里插入图片描述

5.使用代理:
  1. 什么是代理?
    什么是代理?
    代理IP是一个ip ,指的是一个代理服务器。

  2. 要晓得正向代理和反向代理是啥?
    不知道服务器的地址做为判断标准:知道就是正向代理,不知道就是反向代理。
    在这里插入图片描述

  3. 代理ip的分类
    匿名度:
    透明代理 :目标服务器可以通过代理找到你的ip
    匿名代理 :两者之间
    高匿代理 :在爬虫中经常使用,目标服务器无法获取你的ip
    协议:
    根据网站使用的协议不同,需要使用响应的协议代理服务,
    http代理:目标的url为http协议
    https代理:目标url为https协议
    socks代理 :只是简单的传递数据包,不关心是何种协议,比http和HTTPS代理消耗小, 可以转发http和https的请求

  4. 为何使用代理?
    (1)让服务器以为不是同一个客户端在请求
    (2)防止我们的真实地址被泄露,防止被追究

  5. 用法:

    response = requeses.get("http://www.baidu.com, proxies = proxies")
    proxies的形式:字典
    
    例如:
    proxies = {
        "http": "http://192.168.13.24:8000",
        "https": "http://192.168.13.24:8000"
    }

案例:
import requests
url = “http://www.baidu.com”

proxies = {
‘http’:‘http://111.222.11.123:12222’,
}
headers = {“User-Agent”:“Mozilla/5.0 (Windows NT 10.0;.36 (KHTML, like Gecko) Chrome/84.0.414.36”}

response = requests.get(url,proxies=proxies,headers=headers,timeout=5)
print(response.text)

6.cookie与session

(1)requests获取cookie

requests.utils.dict_from_cookiejar:把cookiejar对象转化为字典。

举例:
import requests

url = 'http://www.baidu.com'
response = requests.get(url)
cookie = requests.utils.dict_from_cookiejar(response.cookies)
print(cookie)

cookie是一个字典:
{'ucloud_zz': '1'}

(2)requests处理cookie请求

  1. cookie和session的区别:

    cookie数据存放在客户的浏览器上,session数据放在服务器上
    cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗
    session会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的性能
    单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie
    
  2. 爬虫中为什么要使用cookie:

    1. 带上cookie的好处:
      ①能够访问登录页面。
      ②正常的浏览器在请求服务器的时候肯定会带上cookie(第一次请求除外),所以对方服务器有可能会通过是否携带cookie来判断我们是否是一个爬虫,对应的能够起到一定的反爬作用。
    2. 带上cookie的坏处:
      ①一套cookie往往对应的是一个用户的信息,请求太频繁有更大的可能性被对方识别为爬虫。
      ②一般使用多账号解决。
  3. requests进行携带cookie登录:


    1.cookie字符串放在headers中:
        headers = {
            'User-Agent': 'xxxxx',
            'Cookie': 'xxxxx'
        }
    2.把cookie字典交给requests请求方法的cookies:
        cookies = {‘cookie的name’:‘cookie的value}
		使用方法:
		requests.get(url, headers, cookies=cookie_dict)

(3)requests处理cookie请求之session

requests提供了session类,用来实现客户端和服务的的会话保持!

  1. 会话(状态)保持:
    保存cookie
    实现和服务端的长连接

  2. 使用方法:
    session = requests.session()
    response = session.get(url, headers)

    session在请求一个网站后,对方服务器设置在本地的cookie会保存在session中,下一次在使用session请求对方的服务器的时候,会带上前一次的cookie!

  3. 实战:人人网!

import requests

# 1.实例化session
session = requests.Session()

# 2. 使用session发送post请求,对方服务器会把cookie设置在session中
headers = {"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.3 "}
post_url = "http://www.renren.com/PLogin.do"
post_data = {"email":"自己的账号","password":"自己的密码"}

session.post(post_url,data=post_data,headers=headers)

# 3.请求个人主页,会带上之前的cookie,能够请求成功
profile_url = "http://www.renren.com/自己进自己主页会有的/profile"
response = session.get(profile_url,headers=headers)

with open("renren.html", "w", encoding="utf-8") as f:
    f.write(response.content.decode())




(4)requests模拟登陆的三种方法

   1.session:
        实例化对象
        session.get(url) #cookie保存在session中
        session.get(url) #带上保存在session中cookie

   2.cookie方法在headers中
   3.cookie传递给cookies参数:
        cookie = {"cookie 的name的值":"cookie 的value对应的值"}
  1. requests处理ssl证书:

    ssl证书不安全导致爬虫程序报错,返回ssl.CertificateError(证书错误)
    解决办法:response=requests.get(url, verify = False)
    verify = False 代表不在验证证书,默认是True验证

  2. requests与超时参数(检测IP代理池):

    response=requests.get(url, timeout=3)
    timeout=3,代表保证在3秒钟内返回响应,否则报错

(5)retrying模块(刷新)与超时参数timeout

1.使用retrying模块提供的retry方法
2.通过装饰器的方式,让被装饰的函数反复执行
3.retry中可以传入参数 stop_max_attempt_number,让函数报错后继续重新执行,达到最大执行次数的上限,如果每次都报错,整个函数报错,如果中间有一个成功,程序继续往后执行
import requests
from retrying import retry

headers = {"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/4.0.222.3 "}

@retry(stop_max_attempt_number=3)   # stop_max_attempt_number=3最大执行3次,还不成功就报错
def _parse_url(url):                                            # 前面加_代表此函数,其他地方不可调用
    print("*"*100)
    response = requests.get(url, headers=headers, timeout=3)    # timeout=3超时参数,3s内
    assert response.status_code == 200                          # assert断言,此处断言状态码是200,不是则报错
    return response.content.decode()


def parse_url(url):
    try:
        html_str = _parse_url(url)
    except Exception as e:
        print(e)
        html_str = None
    return html_str

if __name__ == '__main__':
    # url = "www.baidu.com"         这样是会报错的!
    url = "http://www.baidu.com"
    print(parse_url(url))    


无法爬取到的情况:url = “www.baidu.com”!
在这里插入图片描述

正确爬取到的情况:url = “http://www.baidu.com”!

在这里插入图片描述

7.多线程爬虫

(1)多线程爬虫

  1. 思路解析:
    在这里插入图片描述
在python3中,主线程主进程结束,子线程,子进程不会结束
把子线程设置为守护线程,即主线程结束,子线程结束
t1 = threading.Thread(targe=func, args=())
t1.setDaemon(True)
t1.start()    #  线程启动

(2)队列模块的使用(将线程放入队列中实现)

from queue import Queue
q = Queue(masize=100)
item = {}

 # 不等待,直接放(存),队列满的时候会报错
q.put_nowait(item)  

  # 放入数据,队列满的时候会等待
q.put(item)  

# 不等待,直接取,队列空的时候会报错
q.get_nowait()   

# 取出数据,队列空的时候会等待
q.get()    

 #  获取队列中现存数据的个数
q.qsize()  

 # 队列中维持了一个计数,计数不为0时候,让主线程阻塞等待,队列计数为0的时候才会继续往后面执行
q.join()   

q.task_done() 和get()方法配合,队列计数-1
q.put() 队列计数+1