爬虫简介 (爬虫入门小知识点;正式进入爬虫-requests模块的使用;两个实战-使用reques
引言:爬虫?什么是爬虫?
爬虫的定义:模拟浏览器发送请求,获取响应。
书面化爬虫简介!!!点我哦!!!
- 爬虫的作用:
1.数据采集
抓取微博评论(机器学习舆情监控)
抓取招聘网站的招聘信息(数据分析,挖掘)
新浪滚动新闻
百度新闻网站
2.软件测试
爬虫之自动化测试
虫师
3.12306抢票
4.网站上的投票
5.网络安全
短信轰炸
web漏洞扫描
- 爬虫的分类:
根据被爬取的数量不同,分类:
通用爬虫:通常指搜索引擎的爬虫 具有很大的局限性:大部分内容没有用,不同搜索目的,返回的内容相同!
(通用爬虫是搜索引擎抓取系统 (baidu,goole,yahoo等)的重要组成部分 。
主要目的是将互联网的网页下载到本地 ,形成一个互联网内容的镜像备份。)
聚焦爬虫:针对特定网站的爬虫
(是面向特定主题需求的一种网络爬虫程序 ,它与通用搜索引擎爬虫的区别在于 :
聚焦爬虫在实施页面抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息)
根据是否获取数据为目的,分类:
功能性爬虫,比如,投票,点赞
数据增量爬虫,比如招聘信息
根据url地址和对应的页面内容是否改变,数据增量爬虫分类:
基于url地址变化,内容也随之变化的数据增量爬虫
url地址不变,内容变化的数据增量爬虫
- 工作流程:
流程:url——>发送请求,获取响应——>提取数据——>保存数据
发送请求,获取响应——>提取url地址,继续请求
-
robots协议:
robots协议:网站通过robots协议,告诉我们搜索引擎哪些页面可以抓取,哪些页面不能抓取,但它仅仅是道德层面上的约束。 -
http的重点请求头:
http的重点请求头:
user-agent:告诉对方服务器是什么客户端正在请求资源,爬虫中模拟浏览器非常重要的一个手段
爬虫中通过把user-agent设置为浏览器的ua,能够达到模拟浏览器的效果。
cookie:获取登录之后,才能够访问的资源
常见的请求头,响应头
Content-Type
Host(主机和端口号)
Upgrade-Insecure-Rwquests(升级为https请求)
User-Agent(浏览器名称)
Referer(页面跳转处)
Cookie
Authorization(用于表示http协议中需要认证资源的认证信息,如jwt认证)
- 浏览器发送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地址对应的响应为准
- 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 或者 list)
6.发送带参数的请求:
params = {"":""}
url_temp = "不完整的URL地址"
requests.get(url_temp,params=params)
例:wd为百度词条搜索url的参数key值
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页!
应用场景:登录注册
需要传输大文本内容的时候(post请求对长度没有要求)
- 用法:
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()
-
什么是代理?
什么是代理?
代理IP是一个ip ,指的是一个代理服务器。 -
要晓得正向代理和反向代理是啥?
不知道服务器的地址做为判断标准:知道就是正向代理,不知道就是反向代理。 -
代理ip的分类
匿名度:
透明代理 :目标服务器可以通过代理找到你的ip
匿名代理 :两者之间
高匿代理 :在爬虫中经常使用,目标服务器无法获取你的ip
协议:
根据网站使用的协议不同,需要使用响应的协议代理服务,
http代理:目标的url为http协议
https代理:目标url为https协议
socks代理 :只是简单的传递数据包,不关心是何种协议,比http和HTTPS代理消耗小, 可以转发http和https的请求 -
为何使用代理?
(1)让服务器以为不是同一个客户端在请求
(2)防止我们的真实地址被泄露,防止被追究 -
用法:
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)
(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请求
-
cookie和session的区别:
cookie数据存放在客户的浏览器上,session数据放在服务器上 cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗 session会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的性能 单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie -
爬虫中为什么要使用cookie:
- 带上cookie的好处:
①能够访问登录页面。
②正常的浏览器在请求服务器的时候肯定会带上cookie(第一次请求除外),所以对方服务器有可能会通过是否携带cookie来判断我们是否是一个爬虫,对应的能够起到一定的反爬作用。 - 带上cookie的坏处:
①一套cookie往往对应的是一个用户的信息,请求太频繁有更大的可能性被对方识别为爬虫。
②一般使用多账号解决。
- 带上cookie的好处:
-
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类,用来实现客户端和服务的的会话保持!
-
会话(状态)保持:
保存cookie
实现和服务端的长连接 -
使用方法:
session = requests.session()
response = session.get(url, headers)session在请求一个网站后,对方服务器设置在本地的cookie会保存在session中,下一次在使用session请求对方的服务器的时候,会带上前一次的cookie!
-
实战:人人网!
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对应的值"}
-
requests处理ssl证书:
ssl证书不安全导致爬虫程序报错,返回ssl.CertificateError(证书错误)
解决办法:response=requests.get(url, verify = False)
verify = False 代表不在验证证书,默认是True验证 -
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”!
(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










