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

news/2024/7/19 8:40:51 标签: python, 爬虫, selenium

爬虫概述

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

爬虫的分类

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

反爬机制

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

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

反反爬机制

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

requests 基础操作

  • requests 是一个基于网络请求的模块。用来模拟浏览器发请求。
python">import requests

url = '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 设置

python">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请求

python">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 基于网络请求的模块

python"># 基于requests 的图片爬取
import requests

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'
}
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 request

request.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') 直接将请求到的页面源码数据进行解析操作
python">from bs4 import BeautifulSoup

fp = 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:获取指定属性的值。返回列表
python">from lxml import etree

tree = 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')

案例

python">from lxml import etree

page_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'
}).text

tree = 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, . 表示当前div
	content = 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对象至少要发送两次请求)
python">import requests

sess = 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)

代理

python">import requests
from lxml import etree

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'}

# 配置代理
proxies = {'http': '102.129.157.20:8080'}
page_text = requests.get("https://www.sogou.com/web?query=ip",headers=headers, proxies=proxies).text

tree = etree.HTML(page_text)
content = tree.xpath('//*[@id="ipsearchresult"]/strong//text()')
print(content)

代理池

python">import random

proxy_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

异步爬虫

线程池

python">import requests
from multiprocessing.dummy import Pool
import time

urls = ['http://localhost:5000/hello', 'http://localhost:5000/hello', 'http://localhost:5000/hello']
def getRequest(url):
	page_text = requests.get(url).text
	return page_text

start = 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)

生产者消费者模式

python">"""
生产者,消费者模式
"""
from threading import Thread
from queue import Queue
from urllib import request

from lxml import etree
import requests


class 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_queue
        self.img_queue = img_queue

    def run(self) -> None:
        while True:
            if self.page_queue.empty():
                break
            url = self.page_queue.get()
            self.parse_page(url)

    def parse_page(self, url):
        response = requests.get(url, headers=self.headers)
        text = response.text
        html = 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_queue
        self.img_queue = img_queue

    def run(self) -> None:
        while True:
            if self.page_queue.empty() and self.img_queue.empty():
                break
            img_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关键字:可以保证每一个任务对象的阻塞操作可以被异步执行
  • 核心点:如果特殊函数内部的实现语句中出现了不支持异步模块对应的代码,则会立即中断整个异步效果。
python">import asyncio
import time

async 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)

开启多任务异步协程

python">import asyncio
import time


async 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模块代替。异步协程爬虫代码案例:

python">import asyncio
import time

import aiohttp


async 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() => text
            return 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/

环境安装

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

基本操作

python">from selenium import webdriver

from 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()

相关方法

python">"""
## 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()      # 清空控件内容
"""

动作链

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

python">from selenium import webdriver
from time import sleep

bro = 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()

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

python">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.niftyadmin.cn/n/312853.html

相关文章

支付系统设计三:渠道网关设计01-总览

文章目录 前言一、开发框架二、E-R图三、管理后台配置四、运行时执行流程五、屏蔽渠道差异总结 前言 在《支付系统设计一&#xff1a;支付系统产品化》文章中&#xff0c;我们知道支付渠道网关主要具有以下功能&#xff1a; 统一支付出口&#xff0c;提供丰富的支付工具原子能…

【大数据学习篇1】linux常用命令

查看目录下有什么文件信息 //list查看当前目录下有什么文件 ls //list -list 通过详细内容形式查看目录下的文件内容 ls -l 或 ll //查看指定目录下文件名字信息 ls 目录 //以详细列表形式查看指定目录下文件名字信息 ls -l 目录 //list all 查看全部文件&#xff0c;包括隐藏…

KVM存储池管理与磁盘格式

KVM存储池管理与磁盘格式 KVM必须配置一个目录作为存储磁盘镜像&#xff08;存储卷&#xff09;的目录&#xff0c;我们称这个目录为存储池 存储池管理 默认存储池 /var/lib/libvirt/images/ 创建基于文件夹的存储池&#xff08;目录&#xff09; mkdir -p /data/vmfs定义…

C语言实现个人通讯录(功能优化)

实战项目---通讯录&#xff08;功能优化&#xff09; 1.基本思路介绍&#xff1a;1.1基本思路&#xff1a; 2.通讯录的具体实现&#xff1a;2.1 通讯录的建立&#xff1a;2.2通讯录功能&#xff1a; 3.具体功能函数的实现&#xff1a;3.1 增添联系人&#xff1a;3.2 删除联系人…

15.Python Package目录及打包并发布到PyPI

欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; 文章目录 0.基本介绍1.__init__.py文件1.1 Regular Package1.2 namespace package 2.Python Package工程2.1 安装及打包并发布到pypi2.2 将Python文件编译成.so 3.包的搜索路径参考资料 0.基…

RabbitMQ入门案例及简单工程搭建

环境的搭建 这里是用Maven工程搭建的基础环境项目&#xff0c;这里的dome_rabbitmq就是父工程。 子工程 publisher&#xff1a;消息发布者&#xff0c;将消息发送到队列queueconsumer&#xff1a;订阅队列&#xff0c;处理队列中的消息 父工程的pom文件依赖 <?xml ver…

Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置

目录 1、Shader控制一棵草的渲染 2、草地的动态交互 3、使用GPUInstancing渲染大面积的草 4、对大面积草地进行区域剔除和显示等级设置 Unity使用GPU Instancing制作大面积草地效果 大家好&#xff0c;我是阿赵。 这里开始讲大面积草地渲染的第四个部分&#xff0c;对大面积草地…

C/C++每日一练(20230508) 链表专题2

目录 1. 相交链表 &#x1f31f;&#x1f31f; 2. 排序链表 &#x1f31f;&#x1f31f; 3. 重排链表 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. …