【python爬虫一】爬虫基础操作

news/2024/10/31 1:23:39/

爬虫概述

  • 概念:是一种按照一定的规则,自动地抓取互联网上网页中相应信息(文本、图片等)的程序或脚本,然后把抓取的信息存储下来。

爬虫的分类

  • 通用爬虫:把一整张页面源码数据进行爬取
  • 聚焦爬虫:把页面中指定的数据进行爬取
  • 增量式爬虫:监测网站数据更新的情况。
  • 分布式爬虫:基于联合且分布的形式快速进行数据爬取
  • 功能爬虫:刷评论,点赞等功能

反爬机制

作用在web的服务端。制定相关的机制来阻止爬虫对其网站数据的爬取。

  • rebots 协议: 仅仅声明了门户端的哪些数据可被爬,哪些不可被爬。

反反爬机制

作用在爬虫,破解反爬机制。

requests 基础操作

  • requests 是一个基于网络请求的模块。用来模拟浏览器发请求。
import requestsurl = 'https://www.sogou.com/'
# 发起get请求
response = requests.get(url=url)
page_text = response.text
with open('./sogou.html', 'w', encoding='utf-8') as fp:fp.write(page_text)

User-Agent 设置

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
url = 'https://www.sogou.com/web?query=杭州'
response = requests.get(url=url, headers=headers)
page_text = response.text
with open('./hang.html', 'w', encoding='utf-8') as fp:fp.write(page_text)# params 参数
wd = input("enter a keyword:")
params = {'query': wd}
url = 'https://www.sogou.com/web'
response = requests.get(url=url, headers=headers, params=params) # 参数动态化
page_text = response.text# 响应数据为json 则
page_info = response.json()

发送post请求

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
url = 'https://www.sogou.com/web?query=杭州'
data = {'page': 1, 'pageSize': 10}
response = requests.post(url=url, headers=headers, data=data)
page_text = response.json()# 参数为json形式
data = {'page': 1, 'pageSize': 10}
requests.post(url=url, headers=headers, json=data)

urllib 基于网络请求的模块

# 基于requests 的图片爬取
import requestsheaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
img_data = requests.get("https://lmg.jj20.com/up/allimg/tp03/1Z9221U602IE-0-lp.jpg", headers=headers).content # content 返回bytes类型的数据
with open('./123.jpg', 'wb') as f:f.write(img_data)# 基于urllib的图片爬取
from urllib import requestrequest.urlretrieve("https://lmg.jj20.com/up/allimg/tp03/1Z9221U602IE-0-lp.jpg"'./234.jpg')

html 数据解析

bs4基本使用

  • 环境安装
pip install bs4 lxml
  • bs4实现解析的流程:
    • 实例化一个BeautifulSoup的对象,需要把即将解析的页面源码数据加载到该对象中。
    • 调用BeautifulSoup对象中相关的属性和方法进行标签定位和数据的提取
  • BeautifulSoup对象的实例化
    1. BeautifulSoup(fp, 'lxml') 可以将fp表示的一个文件中的数据进行解析操作
    2. BeautifulSoup(page_text, 'lxml') 直接将请求到的页面源码数据进行解析操作
from bs4 import BeautifulSoupfp = open('./test.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')## 标签定位
soup.title # <title>document</title>## 属性定位
soup.find('div', class_='tang') # 返回str
soup.find_all('div', class_='tang') # 返回列表## 选择器定位
soup.select('#feng') #返回列表
soup.select('.tang>ul>li') # 返回列表## 取文本内容
div_tag = soup.select('.tang')[0]
div_tag.text## 取属性
a_tag = soup.find('a', id='feng')
a_tag['href']

总结:
bs4的基本使用:

  • 标签定位:
    • soup.tagName: 只可以返回符合条件的第一个标签
    • soup.find('tagName', attrName='value'): 属性定位。返回值是匹配到的第一个元素
    • soup.find_all('tagName', attrName='value'): 返回匹配到的所以元素。返回列表
    • soup.select('css 选择器') : 返回列表
  • 数据提取:
    • 取标签中存储的数据
      • string:只可以取出标签中直系的文本内容
      • text:可以取的标签中所有的文本
    • 取标签属性的数据
      • tag['attrName']

xpath 解析

  • 解析流程:
    • 实例化一个etree对象,然后把即将被解析的数据加载到该对象中
    • 调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
  • etree对象的实例化
    1. etree.parse(filePath)
    2. etree.HTML(page_text)
  • 标签定位
    • 非最左侧的/:表示一个层级
    • 非最左侧的//:表示多个层级
    • 最左侧的/:必须从根节点开始进行标签定位(/html),表示绝对路径
    • 最左侧的//:可以从任意位置进行标签定位,表示相对路径 **重点
    • 属性定位的写法://tagName[@attrName="value"]
    • 索引定位://tagName[index] 索引是从1开始的
  • 数据提取
    • 提取标签数据
      • //text(): 返回标签下所有节点的数据。包含子节点的文本内容
      • /text():只可以返回直接子节点的文本内容
    • 提取属性数据
      • /@attrName:获取指定属性的值。返回列表
from lxml import etreetree = etree.parse('./test.html') # ElementTree 类型的对象
tree.xpath('/html/head/title')[0]
tree.xpath('/html//title')[0]
tree.xpath('//title')[0]tree.xpath('//div[@class="song"]')
tree.xpath('//div[3]')## 数据提取
tree.xpath('a[@id="feng"]//text()')
tree.xpath('a[@id="feng"]/text()')tree.xpath('a[@id="feng"]//@href')

案例

from lxml import etreepage_text = requests.get("https://www.qiushibaike.com/text/", headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}).texttree = etree.HTML(page_text)
div_list = tree.xpath('//*[@id="content"]/div/div[2]/div')
fot div in div_list:auther = div.xpath('./div[1]/a[2]/h2/text()')[0]  # 局部解析xpath, . 表示当前divcontent = div.xpath('./a[1]/div/span//text()')content = ''.join(content)print(auther, content)
  • xpath 管道符的使用
    • 作用:可以使得xpath表达式具有更强的通用性
    • //div[1]/a/@href | //div[1]/p/a/@href

requests 高级操作

Cookie在爬虫中的应用

  • 手动处理cookie:直接将cookie放在请求头headers中
  • 自动处理:Session对象
    • session的创建:requests.Session()
    • session可以和requests一样调用get和post进行请求发送。如果使用session进行请求发送,则服务端响应后产生的cookie会被自动存储到session对象中。第二次请求时,自动携带存储的cookie。(即:session对象至少要发送两次请求)
import requestssess = requests.Session()
sess.get("https://xueqiu.com/")
sess.get("https://xueqiu.com/statuses/hot/listV2.json?since_id=-1&max_id=156113&size=15", headers=headers)

代理

import requests
from lxml import etreeheaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}# 配置代理
proxies = {'http': '102.129.157.20:8080'}
page_text = requests.get("https://www.sogou.com/web?query=ip",headers=headers, proxies=proxies).texttree = etree.HTML(page_text)
content = tree.xpath('//*[@id="ipsearchresult"]/strong//text()')
print(content)

代理池

import randomproxy_pool = [{'http': '102.129.157.20:8080'}, {'http': '102.129.157.20:8080'}]
page_text = requests.get("https://www.sogou.com/web?query=ip",headers=headers, proxies=random.choice(proxy_pool)).text

异步爬虫

线程池

import requests
from multiprocessing.dummy import Pool
import timeurls = ['http://localhost:5000/hello', 'http://localhost:5000/hello', 'http://localhost:5000/hello']
def getRequest(url):page_text = requests.get(url).textreturn page_textstart = time.time()
pool=Pool(3)
page_list = pool.map(getRequest, urls)
for page_text in page_list:print(len(page_text))print('总耗时:', time.time() - start)

生产者消费者模式

"""
生产者,消费者模式
"""
from threading import Thread
from queue import Queue
from urllib import requestfrom lxml import etree
import requestsclass Producer(Thread):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/112.0.0.0 Safari/537.36'}def __init__(self, page_queue, img_queue, *args, **kwargs):super(Producer, self).__init__(*args, **kwargs)self.page_queue = page_queueself.img_queue = img_queuedef run(self) -> None:while True:if self.page_queue.empty():breakurl = self.page_queue.get()self.parse_page(url)def parse_page(self, url):response = requests.get(url, headers=self.headers)text = response.texthtml = etree.HTML(text)img_list = html.xpath('//*[@id="__layout"]//div[@class="expression-list clearfix"]//img')for img in img_list:img_url = img.xpath('./@data-src')[0]img_name = img.xpath('./@alt')[0] + '.jpg'print(img_name, img_url)self.img_queue.put((img_url, img_name))class Consumer(Thread):def __init__(self, page_queue, img_queue, *args, **kwargs):super(Consumer, self).__init__(*args, **kwargs)self.page_queue = page_queueself.img_queue = img_queuedef run(self) -> None:while True:if self.page_queue.empty() and self.img_queue.empty():breakimg_url, img_name = self.img_queue.get()request.urlretrieve(img_url, f"imgs/{img_name}")print(img_name + "\t 下载完成")def main():page_queue = Queue(3)  # 存储页码链接的队列img_queue = Queue(10)  # 存储解析出来的图片链接# 想要爬取 前 10页的数据for x in range(1, 4):url = f"https://www.doutub.com/img_lists/new/{x}"page_queue.put(url)for x in range(2):t = Producer(page_queue, img_queue)t.start()for x in range(2):t = Consumer(page_queue, img_queue)t.start()if __name__ == '__main__':main()

单线程+多任务的异步协程

  • 特殊的函数
    • 如果一个函数的定义被async关键字修饰,则该函数就是一个特殊的函数。
    • 特殊函数调用后,返回了一个协程对象
    • 函数内部的程序语句没有被立即执行
  • 协程
    • 特殊函数调用后返回的即是协程对象
  • 任务对象
    • asyncio.ensure_future(c)
  • 事件循环:eventLoop
    • asyncio.get_event_loop() 返回事件循环对象
    • 需要将任务对象注册到事件循环对象中,且启动事件循环即可
  • wait()方法
    • 进行任务对象的挂起操作。
    • 可以给每一个任务对象赋予一个可被挂起的权限
    • 挂起:如果挂起一个任务对象就表示让当前正在被执行的任务对象交出cpu的使用权。
  • await关键字:可以保证每一个任务对象的阻塞操作可以被异步执行
  • 核心点:如果特殊函数内部的实现语句中出现了不支持异步模块对应的代码,则会立即中断整个异步效果。
import asyncio
import timeasync def getRequest(url):print("start: ", url)time.sleep(2)print("end. ")return 'aaa'# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)
def callback(res, *args, **kwargs):# 特殊函数的返回值可以使用 result函数接受print("result: ", res.result())# 协程对象
c = getRequest("www.baidu.com")
# 任务对象
task = asyncio.ensure_future(c)
# 任务对象的高级之处: 可以给任务对象绑定回调函数
task.add_done_callback(callback)
# 事件循环对象
loop = asyncio.get_event_loop()
# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(task)

开启多任务异步协程

import asyncio
import timeasync def getRequest(url):print("start: ", url)# time.sleep(2) # 不支持异步模块的代码await asyncio.sleep(2)print("end. ")return 'aaa'# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)
def callback(res, *args, **kwargs):# 特殊函数的返回值可以使用 result函数接受print("result: ", res.result())start = time.time()
urls = ['www.baidu.com', 'www.jd.com', 'www.mi.com']
tasks = []
for url in urls:# 协程对象c = getRequest("www.baidu.com")# 任务对象task = asyncio.ensure_future(c)# 任务对象的高级之处: 可以给任务对象绑定回调函数task.add_done_callback(callback)tasks.append(task)# 事件循环对象
loop = asyncio.get_event_loop()
# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(asyncio.wait(tasks))
print("花费时间: ", time.time() - start) # 2.0086746215820312

aiohttp 支持异步请求操作的模块

pip install aiohttp

requests 模块不支持异步,需要用aiohttp模块代替。异步协程爬虫代码案例:

import asyncio
import timeimport aiohttpasync def getRequest(url):# page_text = await requests.get(url).text   # requests 不支持异步# 基于aiohttp 进行网络请求async with aiohttp.ClientSession() as sess: # 创建一个请求对象"""发起请求的操作:sess.get/post(url, headers, data/params, proxy='http://ip:port')"""async with await sess.get(url) as response:page_text = await response.text()  # read() => content    text() => textreturn page_text# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)
def callback(res, *args, **kwargs):# 此处进行解析html_str = res.result()print("result: ", len(html_str))start = time.time()
urls = ['https://www.baidu.com', 'https://www.jd.com', 'https://www.mi.com']
tasks = []
for url in urls:# 协程对象c = getRequest(url)# 任务对象task = asyncio.ensure_future(c)# 任务对象的高级之处: 可以给任务对象绑定回调函数task.add_done_callback(callback)tasks.append(task)# 事件循环对象
loop = asyncio.get_event_loop()
# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(asyncio.wait(tasks))
print("花费时间: ", time.time() - start)

Selenium

selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 。
selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器。

官网: https://selenium-python.readthedocs.io/
中文文档:https://selenium-python-zh.readthedocs.io/en/latest/

环境安装

  • 下载安装selenium:pip install selenium==3.141.0
  • 下载浏览器驱动程序:
    http://chromedriver.storage.googleapis.com/index.html
  • 下载驱动时,至少要保证大版本对应

基本操作

from selenium import webdriverfrom time import sleep# 1. 创建一个浏览器对象
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
# 2. 发起请求
bro.get("https://www.baidu.com/")
# 3. 标签定位
search_ele = bro.find_element_by_id("kw")
# 4. 节点交互
search_ele.send_keys("Mac Pro")
sleep(2)
btn_ele = bro.find_element_by_xpath('//*[@id="su"]')
btn_ele.click()
sleep(2)# js 注入
bro.execute_script('window.scrollTo(0, document.body.scrollHeight)')
sleep(5)bro.close()

相关方法

"""
## 1. 获取页面内容
bro.page_source## 2. 选择器(find系列)
# ===============所有方法===================
# 1、find_element_by_id   # 通过id查找控件
# 2、find_element_by_link_text  # 通过a标签内容找
# 3、find_element_by_partial_link_text  # 通过a标签内容找,模糊匹配
# 4、find_element_by_tag_name   # 标签名
# 5、find_element_by_class_name  # 类名
# 6、find_element_by_name      # name属性
# 7、find_element_by_css_selector  # 通过css选择器
# 8、find_element_by_xpath       # 通过xpaht选择器## 3. 获取元素属性
# 重点
# tag.get_attribute('href')  # 找当前控件 的href属性对的值
# tag.text   # 获取文本内容## 4. 元素交互
# tag.send_keys()  # 往里面写内容
# tag.click()      # 点击控件
# tag.clear()      # 清空控件内容
"""

动作链

动作链这个工具类中封装好了一些基于浏览器自动化的一系列连续的行为动作(如:滑动,拖拽)

from selenium import webdriver
from time import sleepbro = webdriver.Chrome(executable_path="./chromedriver.exe")
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'bro.get(url)# 这里定位的标签出现在了iframe标签之中,会定位失败, 
# 需要使用 switch_to(frame的ID) 来切换到该frame
bro.switch_to.frame("iframeResult")
div_tag = bro.find_element_by_xpath('//*[@id="draggable"]')# 实例化动作链对象,且让该对象和bro对象进行绑定
action = webdriver.ActionChains(bro)
action.click_and_hold(div_tag)  # 点击且长按
for i in range(5):action.move_by_offset(20, 30).perform()  # perform 表示动作链立即执行sleep(1)sleep(2)
bro.close()

无可视化界面的浏览器操作

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time# 创建一个参数对象,用来控制chrome以无界面模式打开
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')# 创建浏览器对象
browser = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options)
browser.get('https://www.baidu.com/')
time.sleep(3)
# 进行截图
browser.save_screenshot('baidu.png')
browser.close()

http://www.ppmy.cn/news/65801.html

相关文章

Android 音频开发——Audio概览(八)

Audio 是 Android 系统中比较重要的一个模块,在 Android 中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。 一、系统架构 Android 音频架构定义了音频功能的实现方式,并指出实现中所涉及的相关源代码。 应用框架 应用框架包含应用代码,该代码使用 android.me…

PPPoE工作原理

协议原理 数字用户线路DSL(Digital Subscriber Line)是以电话线为传输介质的传输技术,人们通常把所有的DSL技术统称为xDSL,x代表不同种类的数字用户线路技术。目前比较流行的宽带接入方式为ADSL,ADSL是非对称DSL技术,使用的是PPPoE(PPP over Ethernet)协议。 PPPoE(PPP…

tcp cubic 与随机丢包

前面提到过一个 AIMD 的修正方法&#xff0c;“二次机会 MD”&#xff1a;首次丢包只 MD 收缩一个相对较小的比例&#xff0c;再次丢包时再继续收缩&#xff0c;直到 beta * Wmax。 效果如下图&#xff1a; 大意是在检测到丢包时&#xff0c;先 MD 一个相对小的缩放比例&…

电脑缺少msvcp140.dll怎么办,缺少msvcp140一键修复方法

电脑缺少msvcp140.dll怎么办&#xff1f;这个问题相信不少小伙伴都遇到过&#xff0c;msvcp140.dll文件是很多软件跟游戏运行必须用到的文件&#xff0c;如果丢失或者损坏&#xff0c;很多软件都会无法打开运行。其实知道知道方法&#xff0c;修复起来其实也不会很难&#xff0…

路由器配置方法(固定地址)

前言 由于学校给分配了IP地址&#xff0c;因此我们的路由器接入的时候不能选择自动接入方式&#xff0c;而要选择固定地址方式。 step 1 我们首先先将路由器接上网线&#xff0c;这里注意一定要接wan口 因为路由器分为两个口&#xff0c;wan口是入口&#xff0c;lan口是出口…

我们花一个月调研了小红书种草的新机会和增长策略

分析师&#xff1a;Jane、彬超 编辑&#xff1a;yolo 出品&#xff1a;增长黑盒研究组 *本报告为增长黑盒独立研究系列&#xff0c; 与第三方不存在任何利益关系 随着618的临近&#xff0c;小红书再次成为了品牌重要的“营销战场”。面临着经济环境的不确定性&#xff0c;想必各…

性能测试-电商系统tps计算方法【杭州多测师_王sir】【杭州多测师】

怎么计算得出tps指标&#xff1f;1.第一个通过运维那边给的生产数据&#xff0c;看一下生产进件有多少&#xff0c;计算得来的&#xff0c;如果没有生产数据&#xff0c;或者不过就看如下的方法2.第二个就是根据最近一个月的实际访问数据&#xff0c;比如每天调用了多少个接口&…

ChatGPT使用9大技巧详解

目录 技巧1:To Do and Not To Do 技巧2:增加示例 技巧3:使用引导词,引导模型输出特定内容