# python 爬虫学习总结
学习 python 爬虫的一些笔记
# requests 模块
requests 模块流程:
1. 指定url
2. 发起请求 response = requests.get(url)
3. 获取数据 page_source = response.text()
4. 存储数据 文件操作/数据库操作
参数 tips:params 是用来发送查询字符串,而 data 是用来发送正文的。post 与 get 方法的特性是:这两种参数 post()方法都可以用,get 方法只能发查询字符串,不能发送正文
text 返回字符串 content 返回二进制(爬取图片可用) json 返回对象
分页爬取:
如果是 ajax,在检查、网络、xhr 中查看
如果是新链接,可以使用正则表达式匹配 url
如果是用 ajax 的包:要注意的:
- 看请求方法 是 GET 还是 POST。。。
- 看响应头的 content-type 选择 reponse.text () 或 reponse.json ()
- 看负载中带的参数
中文乱码问题(文件编码格式为 utf8 json.dump 时 ensure acill 选项关闭)
什么是 ajax? (根据用户行为重新渲染界面。 不修改 url 在检查 - 网络 - XHR 中查看具体信息)
# bs4 数据解析
bs4 数据解析的原理:
1. 实例化一个 BeautifulSoup 对象 并且将页面原码数据加载到该对象中
2. 通过调用 bs 对象中相关的属性或方法进行标签定位和数据提取
如何实例化 beautifulsoup 对象:
将本地的 html 文档中的数据加载到该对象中
fp = open()
soup = BeautifulSoup(fp,'lxml')
将互联网上获取的页面源码加载到该对象中
page_text = response.text soup = BeautifulSoup(page_text,'lxml')
提供的用于数据解析的方法和属性:
soup.tagname 返回 html 中第一次出现的 tagname 标签
soup.find ('tagname') 等同于 soup.tagname
soup.find ('tagname', class = 'classname') 定义属性位置, class 可以替换为 id attr
soup.find_all ('tagname') 找到符合要求所有标签 返回列表
soup.select ('.tang') 参数为某种选择器(id class 标签),返回一个列表
soup.select ('.tang> ul > li > a') 层级选择器,返回一个列表
soup.selest ('.tang> ul a') > 号表示一个层级,空格表示多个层级
怎么获取标签之间的文本数据:
使用 soup.a.text/string/get_text () 方法
- text/get_text(): 可以获取某一个标签中所有的文本内容(多套几层也能得到)
- string:获取标签下直系的文本内容
怎么获取标签的属性值:
soup.select('tang > ul > li > a')[0]['href']
直接获得 a 标签中的 herf 属性值
# xpath 解析
xpath 解析: 最常用且最便捷高效的一种解析方式。
xpath 解析原理:
1. 实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
2. 调用etree对象中的xpath方法结合xpath表达式实现标签的定位和内容的捕获。
环境安装:
- pip install lxml
如何实例化 etree 对象
from lxml import etree
将本地的 html 文档中的源码数据加载到 etree 对象中:
etree.parse(filePath)
可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text') -xpath('xpath表达式')
/ 表示一个层级 // 表示多个层级
路径后加 [@ 属性名] 精确定位 如 xx_list = tree.xpath('//div[@class='song']')
中括号内加数字代表取第几个(索引下标从 1 开始) xx_list[0]
获取文本:定位后加 /text ()
# 中文出现乱码常见的处理方法
两种常见方法,一般能解决所有中文乱码问题
对爬下来的整个数据改变编码:
response.encoding = 'utf-8'
对出现问题的对象单独进行编码与解码
img_name = img_name.encode('iso-8859-1').decode('gbk')
# selenium 模块
# selenium 模块与爬虫之间具有怎样的关联?
- 便捷的获取网站中动态加载的数据
- 便捷实现模拟登录
# 什么是 selenium 模块
基于浏览器自动化的一个模块。 (编写代码让浏览器完成自动化操作)
# selenium 使用流程:
- 环境安装:pip install selenium
- 下载一个浏览器的驱动程序
- 实例化一个浏览器对象
from selenium import webdriver | |
from selenium.webdriver.edge.service import Service | |
# 实例化一个浏览器对象 参数中的路径为浏览器驱动程序的路径(建议与程序在同一路径下) | |
service = Service(executable_path = './edgedriver.exe') | |
bro = webdriver.Edge(service = service) |
- 编写基于浏览器的代码
# selenium 常用函数
bro.get (url) 让浏览器发起一个指定 url 对应请求
page_text = bro.page_source 获取浏览器当前页面的页面源码数据
标签定位:使用 find_element 方法
search_input = bro.find_element(By.[attrname], "[attr]'s value")
标签交互:
search_input.send_keys('xxx')
执行一组 js 代码
bro.execute_script('code...')
点击按钮:
btn.click()
后退 / 前进
bro.back()/forward()
# selenium 处理 iframe
bro.switch_to.frame('frame_name')
# 动作链 (项目暂时用不到)
南大相关网站的登录还不需要滑块验证
碰到滑块验证的时候可能就需要用到了
# selenium 实现模拟登录
结合前面的基础知识 先点击账号密码登录按钮,找到账号输入框与密码输入框,
输入账号密码,点击登录按钮
# 模拟登陆 cookie 操作
# cookie 有什么作用
TCP/IP 协议是无状态的,因此通常的 get 请求 服务器端不知道你有没有处于登录状态
携带 cookie 值的 get 请求 能使服务器端知道你已经处于登录状态
# 手动 cookie(不推荐)
登录网站后通过抓包工具手动复制 cookie 值 将 cookie 值封装到 headers 中,写死在程序里
缺点:cookie 值一段时间后会过期
# 自动处理
cookie 值是如何产生的?既然 cookie 值能让服务器知道你已经处于登录状态,那么理所当然 cookie 值是登录时发送 post 请求后服务器端生成后发送给客户端的
session 会话对象:
作用:
- 可以进行请求的发送
- 如果请求过程中产生了 cookie,则该 cookie 会被自动存储 / 携带在该 session 对象中
使用:
创建一个 session 对象 :
session = requests.Session()
使用 session 对象进行模拟登录 post 请求的发送 (cookie 就会被存储在 session 中)
session 对象对个人主页对应的 get 请求进行发送(携带了 cookie)
如果登录找不到 post 请求或遇到问题导致获得不到 cookie:
适用 selenium 登录后 用下列方法直接取得 cookie:
c = bro.get_cookies() | |
bro.close() | |
cookies = {} | |
# 获取 cookie 中的 name 和 value, 转化成 requests 可以使⽤的形式 | |
for cookie in c: | |
cookies[cookie['name']] = cookie['value'] |
然后就能用 cookies 了:
response = requests.get(url=detail_url, headers=headers, cookies=cookies) |
# 并行爬取(异步爬虫)
原理:利用进程池实现并行爬取
使用方法:
from multiprocessing import Pool | |
# 创建进程池 | |
pool = Pool(processes=4) | |
pool.map(function_name, iterable[,chunksize]) |
processes 参数设置注意:当进程数量大于 CPU 的内核数量时,等待运行的进程会等到其他进程运行完毕让出内核为止。因此,如果 CPU 是单核,就无法进行多进程并行。在使用多进程爬虫之前,我们需要先了解计算机 CPU 的核心数量。这里用到了 multiprocessing:
from multiprocessing import cpu_count | |
print(cpu_count()) |
运行结果为 16。
使用 eg:
urls = ['https://xjh.haitou.cc/xa/after/page-{}'.format(i) for i in range(1,21)] | |
pool = Pool(processes=4) | |
#get_xuanjing 为参数是一个 url 的爬虫函数 | |
pool.map(get_xuanjiang,urls) | |
pool.close() # 关闭进程池,不再接受新的进程 | |
pool.join() # 主进程阻塞等待子进程的退出 |
# 有关爬虫的一些问题:
爬下来的文本中带有 & nbsp 在 html 中表示 no breaking space(不自动换行的空格)
此时可以采用 str.replace (u'\xa0', '') 来解决 str 为待处理字符串
requests 里.text 与 .content 方法的区别:
两者区别在于,content 中间存的是字节码,而 text 中存的是 Beautifulsoup 根据猜测的编码方式将 content 内容编码成字符串。
直接输出 content,会发现前面存在 b' 这样的标志,这是字节字符串的标志,而 text 是,没有前面的 b, 对于纯 ascii 码,这两个可以说一模一样,对于其他的文字,需要正确编码才能正常显示。大部分情况建议使用.text,因为显示的是汉字,但有时会显示乱码,这时需要用.content.decode ('utf-8'),中文常用 utf-8 和 GBK,GB2312 等。这样可以手工选择文字编码方式。
所以简而言之,.text 是现成的字符串,.content 还要编码,但是.text 不是所有时候显示都正常,这是就需要用.content 进行手动编码
两种常见方法,一般能解决所有中文乱码问题
对爬下来的整个数据改变编码:
response.encoding = 'utf-8'
对出现问题的对象单独进行编码与解码
img_name = img_name.encode('iso-8859-1').decode('gbk')