爬虫简介和requests模块的使用

爬虫介绍

# 写后台--->前端展示数据---》浏览器发送http请求,从后端服务器获取的--》只能从浏览器中看---》看到好看的东西---》保存到本地---》存到我们自己库中----》爬虫


# 百度本质就是一个大爬虫(搜索),在输入框中输入搜索内容,实际是从百度的数据库搜索出来的---》
# 百度数据库的数据是从互联网爬下来的--》百度这个爬虫一刻不停的在互联网爬数据--》爬完就存到它的库里(seo优化--》优化我们的网站能够被搜索引擎先搜到,排的很靠前)--->尽可能被百度爬虫,并且容易搜索到---->seo(免费的)和sem(充钱,把你放前面)---》莆田系医院---->百度快照---》当时爬虫爬取这个网页这一刻,网页的样子---》保留这个网页地址---》当你点击标题--》跳转到这个网页--》完成了你的搜索   伪静态


# 爬虫的本质----》模拟发送http请求(浏览器携带什么,我们也要携带什么)---->服务器返回数据---》对数据进行清洗---》入库   后续操作是别的---》分析数据--》数据分析

# 爬虫协议:君子协议---》大家遵循这个协议,就不违法--》规定了我的网站,什么能爬,什么不能爬
https://www.baidu.com/robots.txt
https://www.cnblogs.com/robots.txt

# 爬虫本质跟用浏览器访问没什么区别

requests模块

# 安装
pip install requests

发送 get 请求

import requests

# 直接请求
res1 = requests.get('https://www.baidu.com')
print(res.text)

# 带请求参数
ip =  '127.0.0.1'
# https://www.svlik.com/t/ipapi/ip.php/?ip=127.0.0.1
res2 = requests.get('https://www.svlik.com/t/ipapi/ip.php',params={'ip': ip})
# params内可以多个,相当于拼接 ?name=lzj&age=18
print(res2.text)

编码和解码

# https://www.baidu.com/baidu?wd=python%E4%B8%ADurl%E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81
# 这个 url 在浏览器中后面的字符就会变成中文的


# 把字典中的中文字段编码
from urllib.parse import urlencode
d = {"wd": 'python中url编码和解码'}
res = urlencode(d)  # wd=python%E4%B8%ADurl%E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81
print(res)


# 只对中文编码和解码
from urllib.parse import quote, unquote
name1 = "编码和解码"
print(quote(name1))  # %E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81

name2 = "wd=python%E4%B8%ADurl%E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81"
print(unquote(name2))  # wd=python中url编码和解码

携带请求头

import requests

# 该请求被禁止 因为没有携带请求头
res = requests.get('https://dig.chouti.com/')
print(res.text)


# 携带请求头
# 请求头
header = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
    "Accept-Encoding": "gzip, deflate, br",
}

res = requests.get('https://dig.chouti.com/', headers=header)
# 可以写入到文件里
with open('chouti.html', 'wb') as f:
    f.write(res.content)
print(res.text)

'''
django 中从 request.META 中取出
参数说明
User-Agent  客户端浏览器类型版本信息等
Referer     上一次请求的地址 功能: 反爬 图片防盗链
'''

携带cookie

# cookie 本身是请求头里面的参数
# 就可以放在请求头中,但是 cookie 经常使用,也可以用单独的 cookies 参数

# 模拟点赞
# 注册登录 https://dig.chouti.com/ 在浏览器上拿到 cookie

header = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
    "Cookie": ""
}
data = {
    "linkId": "34946008",  # 点赞连接的Payload信息
}

# cookies={'key':'value'}  cookie 里面 xx=xxx 改
# res = requests.post('https://dig.chouti.com/link/vote',data=data,headers=header,cookies={'key':'value'})
res = requests.post('https://dig.chouti.com/link/vote',data=data,headers=header)
print(res.text)

发送POST请求模拟登录

# 使用 cookie
import requests

data = {
    'username': '[email protected]',
    'password': 'lqz123',
    'captcha': 'qm4s',
    'remember': 1,
    'ref': 'http://www.aa7a.cn/',
    'act': 'act_login',
}

res = requests.post("http://www.aa7a.cn/user.php",data=data)
print(res.text)
print(res.cookies)  # 登录成功后返回的cookies 以后可以拿着这个cookie 登录

res2 = requests.get("http://www.aa7a.cn/",cookies=res.cookies)
print('[email protected]' in res2.text)

# 每次都需要手动携带cookie  因此使用requests 提供的session

# 使用 session
import requests

session = requests.session()
data = {
    'username': '[email protected]',
    'password': 'lqz123',
    'captcha': 'qm4s',
    'remember': 1,
    'ref': 'http://www.aa7a.cn/',
    'act': 'act_login',
}
res = session.post("http://www.aa7a.cn/user.php",data=data)
print(res.text)
res2 = session.get("http://www.aa7a.cn/")
print('[email protected]' in res2.text)

响应对象

import requests
respone=requests.get('http://www.jianshu.com')

# respone属性
print(respone.text)      # 返回响应体的文本内容
print(respone.content)   # 返回响应体的二进制内容

print(respone.status_code)  # 响应状态码
print(respone.headers)      # 响应头
print(respone.cookies)      # 响应的cookie
print(respone.cookies.get_dict())  # 响应的cookie转成字典
print(respone.cookies.items())

print(respone.url)           # 请求地址
print(respone.history)       #  如果有重定向,列表,放着重定向之前的地址

print(respone.encoding)      # 页面的编码方式:utf-8   gbk
# response.iter_content()    # content迭代取出content二进制内容,一般用它存文件

编码问题

# 请求回来的数据,res.text 打印的时候乱码 ,因为没有指定编码,默认已utf-8编码
# 解决方法
response.encoding='gbk'

获取二进制数据

# 下载图片 视频
import requests

header = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'
}

res = requests.get('https://tva1.sinaimg.cn/mw2000/9d52c073gy1h1v6lmny8nj20j60pjtdh.jpg', headers=header)
with open('mzt.jpg', 'wb') as f:
    # f.write(res.content)
    for line in res.iter_content(100):  # 每次获取多少字节
        f.write(line)

json格式解析

import json
import requests

data = {
    'cname': '',
    'pid': '',
    'keyword': '上海',
    'pageIndex': 1,
    'pageSize': 10,
}

# res = requests.post('http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword',data=data)
# res2 = json.loads(res.text)
# print(type(res2))  # 自动类型
# print(res2['Table'][0]['rowcount'])


res = requests.post('http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword',data=data).json()
print(type(res))
print(res['Table'][0]['rowcount'])

ssl认证

# 之前网站,有些没有认证过的ssl证书,我们访问需要手动携带证书
# 跳过证书直接访问

import requests
respone=requests.get('https://www.12306.cn',verify=False) # 不验证证书,报警告,返回200
print(respone.status_code)

# 手动携带
import requests
respone=requests.get('https://www.12306.cn',
                     cert=('/path/server.crt',
                           '/path/key'))
print(respone.status_code)

使用代理

# 爬虫,速度很快,超过频率限制,使用代理,切换ip,封ip封的也是代理的ip,自己的ip没问题

import requests
proxies = {
    'http': '39.103.217.44:59886',  # http或https代理
}
respone = requests.get('https://www.baidu.com', proxies=proxies)

print(respone.status_code)
请求返回 IP 地址的web
pip3 install django

django-admin startproject crawler_web
cd crawler_web
python3 manage.py startapp app01
# crawler_web/app01/views.py
import json
import requests
from django.http import JsonResponse


# 根据 IP 返回 IP 归属地信息
def ipInfo(ip):
    res = requests.get('https://www.svlik.com/t/ipapi/ip.php', params={'ip': ip}).json()
    country = res.get("country")
    area = res.get("area")
    return country, area


def showIP(request):
    xff = request.META.get('HTTP_X_FORWARDED_FOR')  # 反向代理IP
    remote_addr = request.META.get('REMOTE_ADDR')   # 真实 IP
    if xff:
        country, area = ipInfo(xff)
        info = {"IP": xff, "country": country, "area": area}
        return JsonResponse(info, json_dumps_params={'ensure_ascii': False})
    country, area = ipInfo(remote_addr)
    info = {"IP": remote_addr, "country": country, "area": area}
    return JsonResponse(info, json_dumps_params={'ensure_ascii': False})


# crawler_web/crawler_web/urls.py
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('ip/', views.showIP),
]

sqlite3 版本过低解决办法

 wget https://www.sqlite.org/2019/sqlite-autoconf-3300100.tar.gz
 tar xf sqlite-autoconf-3300100.tar.gz
 cd sqlite-autoconf-3300100/
 ./configure --prefix=/usr/local
 make && make install
 mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
 ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
 echo "/usr/local/lib" > /etc/ld.so.conf.d/sqlite3.conf
 ldconfig
 sqlite3 -version
# 启动
python3 manage.py runserver 0.0.0.0:8000
搭建代理池
# https://github.com/jhao104/proxy_pool
python的爬虫+flask写的
本质使用爬虫技术爬取免费的代理requests模块验证代理是否可以然后存到redis中
起一个web服务器只要访问一个地址他就随机给你一个ip地址

# 步骤
git clone git@github.com:jhao104/proxy_pool.git
pip install -r requirements.txt


'''
  # setting.py 为项目配置文件
  # 配置API服务

  HOST = "0.0.0.0"               # IP
  PORT = 5000                    # 监听端口

  # 配置数据库

  DB_CONN = 'redis://:[email protected]:8888/0'

  # 配置 ProxyFetcher

  PROXY_FETCHER = [
      "freeProxy01",      # 这里是启用的代理抓取方法名,所有fetch方法位于fetcher/proxyFetcher.py
      "freeProxy02",
      # ....
  ]

'''

# 启动爬虫
    python3 proxyPool.py schedule

# 启动webApi服务
    python proxyPool.py server

# 可以使用 docker-compose 直接启动
使用代理池
import json
import requests

# 将代理池部署到服务器上  请求参数参考 github 上
ip = requests.get('http://139.155.237.73:5010/get/').json()['proxy']

proxies = {
    "http": ip,
}

res = requests.get('http://42.194.173.230:8000/ip/', proxies=proxies)

print(res.text)

超时设置

import json
import requests

# 将代理池部署到服务器上  请求参数参考 github 上
ip = requests.get('http://139.155.237.73:5010/get/').json()['proxy']

proxies = {
    "http": ip,
}

res = requests.get('http://42.194.173.230:8000/ip/', proxies=proxies, timeout=3)  # 3s 后无反应抛出异常

print(res.text)

异常处理

from requests.exceptions import *  # 可以查看requests.exceptions获取异常类型

ip = requests.get('http://139.155.237.73:5010/get/').json()['proxy']

proxies = {
    "http": ip,
}
try:
    res = requests.get('http://42.194.173.230:8000/ip/', proxies=proxies, timeout=3)
    print(res.text)         # 内容
    print(res.status_code)  # 状态码
except ReadTimeout:         # timeout=3
    print("ReadTimeout")
except ConnectionError:     # 网络不通
    print("Network Error")
except Timeout:
    print('Timeout')
except Exception:
    print("Error")

认证设置

# 这种很少见,极个别公司内部可能还用这种

import requests
from requests.auth import HTTPBasicAuth
r=requests.get('xxx',auth=HTTPBasicAuth('user','password'))
print(r.status_code)

# HTTPBasicAuth 可以简写为如下格式
import requests
r=requests.get('xxx',auth=('user','password'))
print(r.status_code)

上传文件

# 上传文件,爬虫一般不会用,但是需要使用服务的时候会用 调用别人的

import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)

# django项目
  公司中项目使用了第三方服务第三放服务提供了api接口没提供sdk
  就要使用request发送请求获取数据

# 前端提交一个长链地址  www.cnblogs.com/liuqingzheng/p/233.html ---> 转成短链 ---> x.com/asdf--->存到自己数据库中
# 专门服务,处理长连转短链(go,java ---> 接口 ---> post,带着地址 ---> 返回json,短链地址