爬虫学习笔记1(超级详细)

爬虫学习笔记

2021.5.20

1 爬虫概念

模拟浏览器,发送请求,获取数据

2 爬虫作用

数据采集
软件测试
抢票 抢茅台
网络安全

3 爬虫的分类

数量 是否获取数据 url与数据的关系

4 爬虫的流程

url
发送请求 获取响应
解析url
在这里插入图片描述

如果地址是嵌套的,需点击调到另一个网页的,则需要提取url 再爬

http协议复习

在这里插入图片描述
http是明文传输,容易泄密
https 有ssl进行加密 安全性高 但性能略低

爬虫特别关注的请求头和响应头

请求头
host 域名
connection 长连接
upgrade-Insecure-Requests 升级为https协议
User-Agent 用户代理
Referer 页面跳转处(页面跳转前的链接),防盗链
Cookie 状态保持

Authorization(用于表示HTTP协议中需要认证资源的认证信息,如前面web课程中用于jwt认证)
响应头
Set-Cookie

常见的响应状态码

在这里插入图片描述
所有状态码都不可信,一切以是否从抓包得到的响应中获取到数据为准。
因为网站开发人员有可能设置反爬机制,返回状态码,但不返回数据。
network中抓包得到的源码才是判断依据,elements中的源码是渲染之后的源码,不能作为判断标准

浏览器运行过程

在这里插入图片描述
浏览器获得的是静态页面,后经过浏览器引擎渲染获得最终页面。
红色的是浏览器拿到域名对应的ip ,绿色的是浏览器对ip请求后获取的响应
在这里插入图片描述
注意 爬虫只会请求url地址,对应的拿到url地址的响应(该响应的内容可以是html,css,js图片等)
爬虫不具备渲染能力。(除非借助其他工具或者包进行渲染)
浏览器:发送所有请求,进行渲染
爬虫:只发送指定请求,不会渲染
在这里插入图片描述

如何查找数据

1 html静态文件
2 js/ajax请求
3 css、font 图片
按顺序查找数据
在这里插入图片描述

requests模块

requsets模块官方文档(中文)

1 request模块的作用

发送http请求,获取相应数据
request是第三方模块 需要在你的python虚拟环境进行安装
2 requests模块发送get请求
example:
在这里插入图片描述

在这里插入图片描述
网络传输的字符串都是bytes类型的,所以response.text = response.decode(“推测出的编码字符集”)
使用response.text 需要提前对response 设定解码格式进行解码

import requests

url = "http://www.baidu.com"
response = requests.get(url)
# 对response 手动设定编码格式
response.encoding = “utf8”
# 打印源码的str类型数据 
print(response.text)

# response.content是存储的bytes类型的响应源码,可以进行decode解码操作(二进制到中文格式)
# decode方法默认utf-8 也可使用response.content.decode("GBK")
print(response.content.decode())

在python中,使用unicode类型作为编码的基础类型。即
在这里插入图片描述
decode的作用是将二进制数据解码成unicode编码,如str1.decode(‘utf-8’),表示将utf-8的编码字符串解码成unicode编码。

encode的作用是将unicode编码的字符串编码成二进制数据,如str2.encode(‘utf-8’),表示将unicode编码的字符串编码成utf-8。
在这里插入图片描述

response响应对象的其他常用属性或方法

# coding:utf-8
import requests
url = "https://www.baidu.com"
# 像目标url发送get请求
response = request.get(url)
# 打印响应内容

# 响应对应的请求头
print(response.request.headers)
# 响应头
print(response.headers)
# 打印请求携带的cookies
print(response.request.cookies)
# 打印响应中携带的cookies
print(response.cookies)
# 打印响应的状态码
print(response.status_code)

发送带请求头的请求

requests.get(url,headers = { })
headers参数接收字典形式的请求头,
请求头字段名为key,字段对应的值为value

# coding:utf-8
import requests
url = "https://www.baidu.com"
# 像目标url发送get请求
response = request.get(url,headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 FS"})
print(response.content.decode())

发送带参数的请求

如何查找关键参数
可一个一个的删除参数,直到找到会影响整个查询结果的参数

example:url = “https://www.baidu.com/s?wd=python”
?后面就是参数
发送方式1: ?后直接加参数
发送方式2:使用params构建参数字典
ex:

# coding:utf-8
import requests
url = "https://www.baidu.com"
headers={"User-Agent":" Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 FS"}
# 构建参数字典
data={
'wd':'python'
}
# 像目标url发送get请求
response = request.get(url,headers=headers,params=data)
# 打印返回内容
with open("baidu.html",'wb')as f:
	f.write(response.content)

在headers参数中携带cookie

作用:保持用户访问状态
步骤
1 从浏览器中复制User-Agent和Cookie
2 浏览器的请求字段和值与headers参数必须一致
3 headers请求参数字典中的Cookie键对应的值是字符串

# coding:utf-8
import requests

url = "https://github.com/"
headers = {
    "User_Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 FS',
    "Cookie": '_octo=GH1.1.1029458497.1615336647; _device_id=cdbea1696a9dd9f317cfa16888573ab0; user_session=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; __Host-user_session_same_site=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; logged_in=yes; dotcom_user=zhouchengduizhang; has_recent_activity=1; color_mode={"color_mode":"auto","light_theme":{"name":"light","color_mode":"light"},"dark_theme":{"name":"dark","color_mode":"dark"}}; tz=Asia/Shanghai; _gh_sess=3igVgzqfwGvjnNCAciPP9+WeDwXBZEVu5EmF88HLh5C0GF3g+hfvP5lpEsgyGD1VqG/r/WnoEi8R/7PIkciMapMZE8ilPuUAcWqDzmm/5QhdkqQtbzPYxGxYuOR9vE9cah/JfMRc2pGTkBb42zny9TKlLkkM1MzVH67OALJJ35Dcj3KBXK3H8W76D6PTZyky--aGWlRatVRsB527n+--eKPBbx6c1+XdljJBlCRNkA=='}
response = requests.get(url, headers=headers)

with open("github.html", "wb") as f:
    f.write(response.content)

使用cookies参数保持会话

我们首先要将从浏览器复制的字符串cookie值 转化为字典
再请求的时候将cookies字典赋值给cookies参数

# coding:utf-8
import requests

url = "https://github.com/"
headers = {
    "User_Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 FS',
    # "Cookie": '_octo=GH1.1.1029458497.1615336647; _device_id=cdbea1696a9dd9f317cfa16888573ab0; user_session=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; __Host-user_session_same_site=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; logged_in=yes; dotcom_user=zhouchengduizhang; has_recent_activity=1; color_mode={"color_mode":"auto","light_theme":{"name":"light","color_mode":"light"},"dark_theme":{"name":"dark","color_mode":"dark"}}; tz=Asia/Shanghai; _gh_sess=3igVgzqfwGvjnNCAciPP9+WeDwXBZEVu5EmF88HLh5C0GF3g+hfvP5lpEsgyGD1VqG/r/WnoEi8R/7PIkciMapMZE8ilPuUAcWqDzmm/5QhdkqQtbzPYxGxYuOR9vE9cah/JfMRc2pGTkBb42zny9TKlLkkM1MzVH67OALJJ35Dcj3KBXK3H8W76D6PTZyky--aGWlRatVRsB527n+--eKPBbx6c1+XdljJBlCRNkA=='
}

temp = '_octo=GH1.1.1029458497.1615336647; _device_id=cdbea1696a9dd9f317cfa16888573ab0; user_session=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; __Host-user_session_same_site=QgcLkcLX9aqE5jXkXcvPt2jHmeEq-_H41N_wtC7yy-B8m70O; logged_in=yes; dotcom_user=zhouchengduizhang; has_recent_activity=1; color_mode={"color_mode":"auto","light_theme":{"name":"light","color_mode":"light"},"dark_theme":{"name":"dark","color_mode":"dark"}}; _gh_sess=qt4JaIvs2gL6wR8gwia16yPzoEey0gR8B3xdLm+S/1lC601UZizs12/KL+BCWkCOyCi1W7Ooy4eOYqSTu1n6dMLHFguDa635swBs8LzDi/rRsMVEAMWIycBstQcMF44Q3nAXWKQe5/o/O+VT2HyGZd08qH//rTxHWdxDthYTlnlFngSiHPDqEipPkadj0S4a--cUhux0/HUMCrJSu9--apA4hVTNvyHgLQ1D2uHAfQ==; tz=Asia/Shanghai'

# 普通方案 先切割成键值对 以逗号空格进行分割
cookie_list = temp.split('; ')
cookies = {}
# for cookie in cookie_list:
#     cookies[cookie.split('=')[0]] = cookie.split('=')[-1]

# 高级方案
cookies = {cookie.split('=')[0]: cookie.split('=')[-1] for cookie in cookie_list}

print(cookies)
response = requests.get(url, cookies=cookies)

with open("github1.html", "wb") as f:
    f.write(response.content)
print("success")

此处request拥有header报错,故删除了header 原因未知

CookieJar对象转换为cookies字典的方法

使用request获取的response对象,具有cookies属性,该属性值是一个cookieJar类型,包含了对方服务设置在本地的cookie。我们如何将其转换为cookies字典呢?
1 转换方法

# coding:utf-8
import requests

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

# 转化为cookie字典
dict_cookies = requests.utils.dict_from_cookiejar(response.cookies)

# 字典转化成cookiejar 会丢失域名
jarcookies = requests.utils.cookiejar_from_dict(dict_cookies)
print(jarcookies)

超时参数timeout的使用

一个请求如果长时间没有响应,就会浪费时间,我们可通过timeout进行强制要求,让他必须在特定的时间返回结果,否则报错。避免浪费时间

1 超时参数timeout的使用方法

response = requests.get(url,timeout=3)

timeout= 3 表示发送请求后,3s内返回响应,否则抛出异常

# coding:utf-8
import requests

url = 'http://twitter.com'
response = requests.get(url, timeout=3)

在这里插入图片描述

代理使用的过程

在这里插入图片描述

正向代理和反向代理的区别

是否知道最终服务器地址为正向代理和反向代理的判断标准
1为浏览器或者客户端(发送请求的一方)转发请求的,叫做正向代理
浏览器知道最终处理请求的服务器的真实ip地址,例如vpn
2为最终服务器转发请求的,叫做反向代理
浏览器不知道服务器的真实地址,例如nginx

代理ip的分类

爬虫一般使用高匿代理
1 根据匿名度分类
在这里插入图片描述
2 根据协议分类
在这里插入图片描述

proxies代理参数的使用

为了让服务器以为不是同一个客户端在请求,防止频繁向一个域名发送请求被封ip,所以我们需要所以代理ip

用法:
1 直接在网络搜索代理ip
如果代理网站ip不能复制
谷歌浏览器查看源码
点击在这里插入图片描述
再点击需要复制的ip的位置
在这里插入图片描述
右上角源码中即可复制
在这里插入图片描述

# coding:utf-8
import requests

url = "http://www.baidu.com"

proxies = {
    'https': '180.120.147.67:65532'
}
response = requests.get(url, proxies=proxies, timeout=3)

print(response.text)

使用verify参数忽略CA证书
在这里插入图片描述
原因:该网站的CA证书没有经过机构认证
这种网站爬虫无法访问
除非使用verify参数

# coding:utf-8
import requests

url = "https://sam.huat.edu.cn:8443/selfservice/"

response = requests.get(url, verify=False, timeout=3)

print(response.text)

request发送post请求

发送方法
在这里插入图片描述

POST请求练习

# coding:utf-8
import requests
import json


# 面向对象 便于后期扩展
class King(object):
    def __init__(self, word):
        self.url = 'https://ifanyi.iciba.com/index.php?c=trans&m=fy&client=6&auth_user=key_ciba&sign=0624177fcae097f7'

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/90.0.4430.93 Safari/537.36 FS',
        }
        self.data = {
            "from": "zh",
            "to": "en",
            "q": word,
        }

    def get_data(self):
        response = requests.post(self.url, data=self.data, headers=self.headers, verify=False)

        return response.content

        # print(1111)

    def parse_data(self, data):
        # loads方法将json字符串转换成python字典
        dict_data = json.loads(data)

        print(dict_data)

    def run(self):
        # 编写爬虫逻辑

        # url
        # headers
        # data字典
        # 发送请求获取响应
        response = self.get_data()

        # json数据解析
        print(response.decode('utf-8'))
        # self.parse_data(response)


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

目前遇到验证失败问题 ,应该是翻译网站做了反爬 具体等以后再攻破

post数据来源

需多次抓包进行判断
1 固定值 抓包比较不变值
2 输入值 抓包比较变值
3 预设值-静态文件 需要提前从静态html中获取 (例如token)
4 预设值-发请求 需要对指定地址发送请求获取数据
5 在客户端生成的 分析js 模拟生成数据 (较高难度爬取)

使用request.session进行状态保持

1 requests.session的作用以及应用场景
自动处理cookie
场景
连续的多次请求

使用方法:
模仿github登陆
一般为了防止点击登录按钮,浏览器抓包内容被清空,需要点击Preserve按钮
在这里插入图片描述

# coding:utf-8
import requests
import re


def login():
    # session
    session = requests.session()

    # headers
    session.headers = {
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 '
        'Safari/537.36 FS'}

    # url1-获取token
    url1 = 'https://github.com/login'
    # 发送请求获取响应
    res_1 = session.get(url1).content.decode()
    # 正则提取(利用正则表达式).匹配所有,*指多个,?指非贪婪模式就行截取
    token = re.findall('name="authenticity_token" value="(.*?)" />', res_1)
    print(token)

    # url2 登陆  这里获得cookie
    url2 = 'https://github.com/session'
    # 构建表单数据
    data = {"commit": "Sign in",
            "authenticity_token": token,
            "login": "你自己的登陆名",
            "password": "密码",
            " webauthn - support": "supported"}
    print(data)
    # 发送请求登陆 这里已经携带cookie
    session.post(url2, data=data)
    # url3-验证
    url3 = 'https://github.com/zhouchengduizhang'
    response = session.get(url3)
    with open("github.html", 'wb') as f:
        f.write(response.content)


if __name__ == '__main__':
    login()

这里应该实现cookie登陆 不过结果貌似没有实现 原因等找到回来在解决

正则贪婪模式与非贪婪模式讲解

数据提取

响应分类

结构化数据:
json数据(高频出现)
可以利用json模块 re模块 jsonpath模块提取
xml数据(低频出现)
可以利用re模块 lxml 模块提取
在这里插入图片描述
非结构化数据:
html数据 (无规律 带有文字或者图片文件 位置不同)
re模块(正则)
lxml模块(xpath语法)

在这里插入图片描述
xml与html的区别
xml是一种可拓展标记语言,专注于对数据的传输和存储,侧重点是数据内容本身。标签可自行定义,但html是写死的,固定的标签表示固定的意思
html是超文本标记语言为了更好的显示数据 侧重点是为了显示
在这里插入图片描述

json模块的使用

jsonpath使用场景:多层复杂字典
安装;pip install jsonpath
jsonpath模块提取数据的方法
from json import jsonpath
ret = jsonpath(a,‘jsonpath语法字符串’)
语法
$ 根节点(最外层的大括号)
. 子节点
… 内部任意位置,子孙节点
在这里插入图片描述
data必须是字典对象
例子:爬取拉钩网地点数据
数据格式:(嵌套较多)
在这里插入图片描述

# coding:utf-8
import requests
import jsonpath
import json

headers = {
    'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/90.0.4430.93 " \
                  "Safari/537.36 FS"}
response = requests.get('https://www.lagou.com/lbs/getAllCitySearchLabels.json', headers=headers, verify=False)
# 将字节类型的content变为字典
dict_data = json.loads(response.content)
# 打印A下面的name数据
# print(jsonpath.jsonpath(dict_data,'$..A..name'))
print(jsonpath.jsonpath(dict_data, '$..name'))

在这里插入图片描述

lxml模块的使用

lxml模块可以利用XPath规则语法,来快速定位HTML\XML中的特定元素以及获取节点信息(文本内容,属性值)
XPath(XML Path language)是一门在HTML\XML文档中查找信息的语言,可用来在HTML\XML文档中对元素和属性进行遍历
提取xml,html中的数据需要lxml模块和xpath语法配合使用

谷歌浏览器xpath helper插件的安装和使用

xpath helper插件可以帮我们练习xpath语法
先安装xpath拓展程序,
1 下载xpathhelper拓展程序
2 解压后拖入到谷歌工具拓展程序中

xpath基础语法

每个html,xml的标签我们都称为节点,其中最顶层的节点称为根节点。

节点语法
/绝对路径
//相对路径 从全文档中选
.当前节点
…上一层节点
@ 选取属性(添加在末尾进行数据提取)
text()选取文本(添加在末尾)
斜杠隔开的是节点 被选中的标签会有highlight显示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

xpath修饰语法 - 选取特定节点的语法

标签+语法
xpath 第一个元素的位置是1
通过索引[n] n为数字
[last()]最后一个[ ]前的标签
[last()-1] 选中倒数第二个
[position()>=10] 范围选择
在这里插入图片描述
使用属性值来寻找节点
[@+标签属性值]
在这里插入图片描述
使用包含的内容来找下一页
//span[contains(text(),“一页”)]
在这里插入图片描述

lxml模块的使用

安装: pip install lxml
提取方法:
1导入lxml的tree库
from lxml import etree
2 利用etree.HTML,将和html字符串(byte类型或者str)转化为Elements对象,Elements对象具有xpath的方法,返回结果的列表

html = etree.HTML(text)
ret_list = html.xpath("xpath语法规则字符串")

3.xpath方法返回列表的三种情况
返回空列表:根据xpath语法规则字符串,没有定位到任何元素
返回字符串构成的列表:xpath字符串规则匹配的一定是文本内容或某属性的值
返回由Elements对象构成的列表:xpath规则字符串匹配的是标签,列表中的Elements对象可以继续进行xpath

# coding:utf-8
from lxml import etree

text = '''
<div>
    <ul>
        <li class="item-1">
            <a href="link1.html">first item</a>
        </li>
        <li class="item-1">
            <a href="link2.html">second item</a>
        </li>
        <li class="item-2">
            <a href="link3.html">tired item</a>
        </li>
    </ul>
</div>
'''

# 创建element对象
html = etree.HTML(text)

# print(html.xpath('//a[@href="link1.html"]/text()'))
# print(html.xpath('//a[@href="link1.html"]/text()')[0])
# print(dir(html))

# 用法1
text_list = html.xpath('//a/text()')
link_list = html.xpath('//a/@href')

# for text in text_list:
#     # 索引 .index方法 获得列表索引
#     myindex = text_list.index(text)
#     link = link_list[myindex]
#     print(text, link)

# 用法2
# 注意zip用法
# 以相同的索引遍历两个列表
for text, link in zip(text_list, link_list):
    print(text, link)


# 用法3
# 定位到a标签
el_list = html.xpath('//a')
for el in el_list:
	print(el.xpath('./text()')[0],el.xpath('./@href')[0])
	print(el.xpath('.//text()'))
	print(el.xpath('text()'))

未完待续 请期待爬虫学习笔记2

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值