# 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 对象:

  1. 将本地的 html 文档中的数据加载到该对象中

    fp = open()
    soup = BeautifulSoup(fp,'lxml')
  2. 将互联网上获取的页面源码加载到该对象中

    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

  1. 将本地的 html 文档中的源码数据加载到 etree 对象中:

    etree.parse(filePath)

  2. 可以将从互联网上获取的源码数据加载到该对象中

    etree.HTML('page_text') -xpath('xpath表达式')

/ 表示一个层级 // 表示多个层级

路径后加 [@ 属性名] 精确定位 如 xx_list = tree.xpath('//div[@class='song']')

中括号内加数字代表取第几个(索引下标从 1 开始) xx_list[0]

获取文本:定位后加 /text ()

# 中文出现乱码常见的处理方法

两种常见方法,一般能解决所有中文乱码问题

  1. 对爬下来的整个数据改变编码:

    response.encoding = 'utf-8'
  2. 对出现问题的对象单独进行编码与解码

    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 会话对象:

作用:

  1. 可以进行请求的发送
  2. 如果请求过程中产生了 cookie,则该 cookie 会被自动存储 / 携带在该 session 对象中

使用:

  1. 创建一个 session 对象 : session = requests.Session()

  2. 使用 session 对象进行模拟登录 post 请求的发送 (cookie 就会被存储在 session 中)

  3. 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 进行手动编码

  • 两种常见方法,一般能解决所有中文乱码问题

    1. 对爬下来的整个数据改变编码:

      response.encoding = 'utf-8'
    2. 对出现问题的对象单独进行编码与解码

      img_name = img_name.encode('iso-8859-1').decode('gbk')
更新于

请我喝[茶]~( ̄▽ ̄)~*

MikeMao 微信支付

微信支付

MikeMao 支付宝

支付宝

MikeMao 贝宝

贝宝