【爬虫系列】Python 爬虫入门(2)

news2024/12/23 17:27:37

接上篇,继续梳理 Python 爬虫入门的知识点。这里将重点说明,如何识别网站反爬虫机制及应对策略,使用 Selenium 模拟浏览器操作等内容,干货满满,一起学习和成长吧。

1、识别反爬虫机制及应对策略

1.1 测试网站是否开启了反爬虫

随着互联网技术的日益革新,大多数的网站都会使用反爬虫机制。我们在爬取目标页面之前,第一步就是要识别需不需要应对网站的反爬虫,常见的测试方式有:

<1>、使用 requests 模块提供的 API

# 以get方式发送请求,暂时不加入请求头
response = requests.get(url)
if response.status_code != 200:
    print(f"网站开启了发爬虫机制,响应状态为{status_code}")

<2>、使用爬虫框架提供的测试命令

以 Scrapy 框架为例,需先下载该依赖(pip install Scrapy),接着在 CMD 命令行 或 其他终端键入测试命令: 

Scrapy shell 目标url

如果上述的测试返回响应码为200,说明网站不存在反爬虫机制,如果是其他的响应码类型,需要具体分析对应哪种反爬虫机制。

响应状态码

这里,顺带普及下响应状态码 Status Code 的内容,它是用 3 位十进制数表示,以代码的形式表示服务器对请求的处理结果。现行的 RFC 标准把状态码分成了五类,用数字的第一位表示分类,范围在100~599 之间。这五类的具体含义,如下:

1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
2××:成功,报文已经收到并被正确处理;
3××:重定向,资源位置发生变动,需要客户端重新发送请求;
4××:客户端错误,请求报文有误,服务器无法处理;
5××:服务器错误,服务器在处理请求时内部发生了错误。

最常用的状态码有,200(成功),301(永久移动),302(临时移动),400(错误请求),401(未授权),403(请求被禁止),404(未找到),500(服务器内部错误)。使用爬虫过程中,遇到最多的则是 200 和 403 了。

当然,目前 RFC 标准里总共有 41 个状态码,但状态码定义是开放的,允许自行扩展。因此像 Apache、Nginx 等 Web 服务器都定义了一些专有的状态码。如果自己开发 Web 应用的话,也可以在不冲突的前提下定义项目专有的状态码。

1.2 User-Agent检查

在上篇已经介绍过,检查 User-Agent 是一种最简单且最常见的反爬虫策略,网站会检查发送的请求中是否存在请求头信息,如果检查不存在的话,网站服务器会拒绝请求!

应对策略也很简单,发送请求的时候加上请求头信息即可,如下:

import requests
from fake_useragent import UserAgent


# 请求头
headers = UserAgent(path="D:\\XXX\\reptile\\fake_useragent.json").google
# 发送请求
response = requests.get(url, headers)
# 获取整个html文档
html = response.text
print(html)

1.3 访问频率检查

通常情况下,人工去点击页面,不会在1s内访问几十甚至上百个网页,也不会有类似 5s/次 访问页面的精确操作,一旦识别到这类情况,网站则会怀疑你是机器人,就会触发反爬虫机制,拒绝这种高频次或精准性的请求操作。

应对这种情况,根据这种机制特征,我们需要设置随机的访问时间间隔,降低请求网站的频率(最好考虑目标网站的访问承受能力,不要把人家搞崩了~)。当然,也可以使用 Selenium 模拟浏览器操作,该模块的使用在后面再详细的说明,这里不展开。

1.4 Session访问限制

我们知道 HTTP 是一种无状态的协议,为了维持客户端与服务器之间的通信状态,使用 Cookie 技术来保持双方的通信状态。有些网站的网页是需要登录才允许爬取数据的,而登录的原理就是浏览器首次通过用户名密码登录之后,服务器给客户端发送一个随机的 Cookie,下次浏览器请求其它页面时,就把刚才的 Cookie 随着请求一起发送给服务器,这样服务器就知道该用户已经是登录用户。

应对这种情况,需要调整下爬虫代码,使用带 Session 会话的请求登陆,然后再访问目标网页,如下:

import requests

# 构建Session会话
session = requests.Session()
# 通过post请求登陆
session.post(login_url, data={username, pwd})
# 访问目标网页
r = session.get(home_url)
# 释放会话资源
session.close()

当构建一个 Session 会话之后,客户端第一次发起请求登录账户,服务器自动把 Cookie 信息保存在 Session 对象中,发起第二次请求时 requests 自动把 Session 中的 Cookie 信息发送给服务器,使之保持通信状态。

1.5 IP访问限制

有些网站为了不让你爬取,可能会精准识别你的 IP 操作。比如,如果发现短时间内该 IP多次访问同一个页面,则会判定你在使用爬虫,触发网站的反爬虫,则会封杀你的 IP(至于永久封杀还是一定时间内不能再次访问,看具体网站的策略了~)。这种情况不好识别,因为当你意识到这种情况时,你当前 IP 可能无法继续访问了。

当然,应对这种情况,通过代理 IP 可以迎刃而解。我们可以爬取网上公开且免费的代理 IP,有了大量代理 IP 后可以每请求几次更换一个 IP,这样就能继续之前的爬虫操作了。

import requests
import re

def get_ip_list(url, headers, pattern):
    ip_list = []
    response = requests.get(url, headers)
    if response.status_code == 200:
        html = response.text
        # 按正则先匹配到提取的范围
        match_all_data = re.findall(pattern, html)
        for i in range(len(match_all_data)):
            # 对每一条url进行精准匹配,可根据具体的情况进行分析
            url = re.findall(pattern, match_all_data[i])
            ip_list.append(url)
    return ip_list

这里,为了能最有效率的利用这些代理 IP,爬取完成后可以考虑放到数据库保存,每次使用时先从数据库里拿。另外,当数据库里可用的代理 IP 数量低于某个阈值时,可以考虑再爬取一批代理 IP,用于更新或补充自己的 IP 池,这样 IP 池里就会保持处于可用状态。

1.6 验证码校验

生活中,我们看到的验证码可谓五花八门,主要类型有:随机数字图片验证码、滑动验证码、手机验证码、邮箱/手机号组合验证等。网站通过常规验证码和滑动验证码的校验,可以区分人机操作,并防止恶意注册、暴力破解、刷票、论坛灌水、黑客攻击等行为;而通过手机号码、邮箱手机号组合等校验,主要是验证用户信息,保护用户信息安全。对于爬虫而言,自动爬取后两种的网页数据就无能为力了,一般是对前两种验证码策略的应对。

随机数字图片验证码,又可以细分很多小类型,需要根据不同的类型采取不同的策略。比如,字母/数字组合类型(Z5f0ty)、计算题类型(1+5=?),这种简单的验证码可通过机器学习识别。又比如,图片验证类型,这种复杂的验证码可通过专门的付费打码平台人工打码。

滑动验证码,采用的是高精度人机行为识别技术,用户只需向右滑动拼图,补齐缺块儿,即可完成验证,这种可以使用 Selenium 模拟浏览器执行滑动操作。

1.7 动态网页

有时候,我们使用 requests 模块获取网页内容会很少,并且也不包含我们采集的目标数据,这是因为页面展示的实时信息是动态渲染的,比如股票行情实时的数据、证券交易公开的数据等。面对这种动态的网页,使用 requests 模块就不再适合了。

我们使用浏览器的【开发者工具】定位看到的数据,有可能是动态渲染过的,也有可能不是。那么,该如何识别网页上的数据是不是动态渲染的呢?方法很简单,通过右键点击网页空白处,选择【查看网页源代码】,将页面上的数据复制后去源代码里搜索,如果搜索不到则可以判定是动态渲染的!应对这种反爬策略,我们仍可以选择使用 Selenium 模拟浏览器操作获取数据。

我们随便搜索一个财经网站测试下,通过【开发者工具】能看到 88.28 指数是存在的,如下:

去【查看网页源代码】搜索 88.28 ,显示这个指数不存在: 

说明当前网页是动态渲染的,可以考虑使用 Selenium 模块去爬取。

1.8 数据API加密

爬虫和反爬虫本质上是一种攻防关系,如果网站真心不让你爬取自己的页面数据,则会使用难度更大,破解更复杂的反爬策略。

比如,前端 JS 加密。网站花了一番心思的加密操作,相对于爬取方来说,也是需要一定时间和分析能力才能进行解密,极大的增加了爬取的难度。

又比如,网站使用多个不同的字体文件加密,只有使用约定的字体文件方式才能解密。网站服务端根据字体映射文件,先将客户端查询的数据进行转换再传给前端,前端根据字体文件进行逆向解密,映射方式可以自由选择,比如数字乱序显示等。这样爬虫可以正常爬取,但得到的数据却是错误的!

所谓的道高一尺,魔高一丈,恐怕不过如此吧,哈哈哈~

2、Selenium模块

2.1 选择 Requests 还是 Selenium ?

从上面介绍的反爬应对策略不难发现,当 Requests 模块解决不了的爬取问题,使用 Selenium 模块基本可以解决。到这里可能会产生疑问:这两个模块都是爬虫的核心库,为什么不直接使用 Selenium 替代 Requests 做所有的爬虫操作呢?

这是因为 Requests 模块是直接访问网页,爬取速度非常快,而 Selenium 模块要先打开模拟浏览器再访问网页,爬取速度相对较慢。实际使用中,肯定会优先考虑使用 Requests 模块,而 Requests 模块解决不了的话再使用 Selenium 模块。

如果说 Requests 模块可以爬取50%的网站,那么 Selenium 模块可以爬取95%的网站,大部分爬取难度较高的网站都可以用它爬取。

2.2 Selenium 该怎么用?

Selenium 是一个用于 Web 应用程序测试的工具,它能够驱动浏览器模拟用户的操作,比如鼠标点击、键盘输入等行为,支持的浏览器包括 IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge 等。通过 Selenium 模块能比较容易地获取网页源代码,还能自动下载网络资源。

首先,需要下载 Selenium 模块,如下:

pip install selenium

接着,下载和安装浏览器驱动程序,不同的浏览器驱动下载地址,参考如下(按需选择):

  • Edge:Microsoft Edge WebDriver - Microsoft Edge Developer
  • Chrome:https://chromedriver.storage.googleapis.com/index.html
  • Firefox:Releases · mozilla/geckodriver · GitHub
  • Safari:WebDriver Support in Safari 10 | WebKit

下载的浏览器驱动需要与当前使用的浏览器版本保持一致,我用的是 Google 浏览器,通过【设置】--【关于 Chrome】,可以查看版本号:

找到自己需要的驱动路径,下载:

下载完成后,解压 zip 包会得到一个 chromedriver.exe,将这个可执行文件放到 Python 的 Scripts 目录下就完成了安装。验证是否成功安装驱动,可以打开 CMD,输入命令,验证如下:

到此,万事俱备,就可以小试牛刀了。

打开 Google 浏览器,并访问百度的首页,在获取网页源代码后,等待30s,最后关闭浏览器。以这个操作流程为例,测试代码如下:

from selenium import webdriver

def test_open_browser(url):
    # 打开 Google 浏览器
    browser = webdriver.Chrome()
    # 访问目标网址
    browser.get(url)
    # 获取网页源代码
    data = browser.page_source
    # 休眠30s(智能等待)
    browser.implicitly_wait(30)
    # 关闭浏览器
    browser.quit()

这样就能轻松获取网页源代码数据了。如果不需要弹出模拟浏览器窗口,就能获取网页源代码,可启用无界面浏览器模式(Chrome Headless),在打开 Google 浏览器的代码之前,新增和修改如下代码:

co = webdriver.ChromeOptions()
co.add_argument('--headless')
browser = webdriver.Chrome(options=co)

browser 还有更多 API 可以自行尝试,接下来会进行一些用法总结。

2.3 Selenium 操作模拟浏览器小结

除了访问网页,Selenium 模块还可以进行其他行为操作。该模块 API,常用的属性有:

  • browser.window_handles:获取浏览器所有窗口的句柄
  • browser.current_window_handle:获取当前浏览器窗口的句柄
  • browser.name:获取当前浏览器驱动的名称
  • browser.page_source:获取网页源代码
  • browser.title:获取当前网页的标题
  • browser.current_url:获取当前网页的网址

常用的操作方法有:

  • browser.maximize_window():窗口最大化
  • browser.minimize_window():窗口最小化
  • browser.set_window_size(width, height):设置窗口尺寸
  • browser.forword():前进
  • browser.back():后退
  • browser.switch_to_frame("f1"):切换到内嵌框架(用法即将废弃)
  • browser.switch_to.frame("f1"):切换到内嵌框架
  • browser.switch_to_window("w1"):切换到内嵌窗口(用法即将废弃)
  • browser.switch_to.window("w1"):切换到内嵌窗口(一般与browser.window_handles搭配使用)
  • browser.get_cookies():获取当前网页用到的cookies
  • browser.refresh():刷新当前网页
  • browser.close():关闭浏览器
  • browser.find_element_by_xxx("").send_keys():模拟键盘输入
  • browser.find_element_by_xxx("").click():点击对象
  • browser.find_element_by_xxx("").submit():提交对象的内容
  • browser.find_element_by_xxx("").text:获取文本信息
  • browser.find_element_by_xxx("").clear():清除对象的内容

find_element_by_xxx() 用于定位网页元素,有很多使用方法,如下:

注意:

如果xxx是xpath的话,格式为:

        browser.find_element_by_xpath('XPath表达式')

如果xxx是css_selector的话,格式为:

        browser.find_element_by_css_selector('CSS选择器')

实际使用中,二者都常用来定位网页元素,根据需要进行选择。

XPath 如何使用?

XPath 可理解为网页元素的名字或 ID。find_element_by_xpath() 函数可根据 XPath 表达式定位网页元素,利用开发者工具,可获取网页元素的XPath表达式,如下:

 键盘事件:包括键盘tab、回车、ctrl键等

from selenium.webdriver.common.keys import Keys

# Tab 切换到密码框
browser.find_element_by_class_name("username").send_keys(Keys.TAB)
# ENTER 回车登陆
browser.find_element_by_class_name("password").send_keys(Keys.ENTER)
# 全选、复制、剪切等
browser.find_element_by_name("input").send_keys(Keys.CONTROL, 'a')
browser.find_element_by_name("input").send_keys(Keys.CONTROL, 'c')
browser.find_element_by_name("input").send_keys(Keys.CONTROL, 'x')

鼠标事件:包括鼠标右键、双击、拖动、移动鼠标到某个元素上等

from selenium.webdriver.common.action_chains import ActionChains

elem = browser.find_element_by_xpath("")
# 鼠标点击行为
ActionChains(browser).click(elem).perform()  # 单击,默认左击
ActionChains(browser).double_click(elem).perform()  # 双击
ActionChains(browser).context_click(elem).perform()  # 右击
ActionChains(browser).click_and_hold(elem).perform()  # 单击并停留
# 鼠标拖动
to_elem = browser.find_element_by_xpath("")
ActionChains(browser).drag_and_drop(elem, to_elem).perform()
ActionChains(browser).move_to_element(elem).perform() # 鼠标悬停
ActionChains(browser).move_by_offset(x, y).perform() # 鼠标移动,需要指定x,y轴的偏移量

Expected Conditions:期望的条件,可用来判断浏览器的动态页面元素出现和消失情况,经常与 WebDriverWait 搭配使用,通过以下方式引入:

from selenium.webdriver.support import expected_conditions as EC

常用 API 有:

  • title_is:判断当前页面的 title 是否精确等于预期;
  • title_contains:判断当前页面的 title 是否包含预期字符串;
  • presence_of_element_located:判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见;
  • visibility_of_element_located:判断某个元素是否可见.可见代表元素非隐藏,并且元素的宽和高都不等于0;
  • visibility_of:跟上面的方法做一样的事情,只是上面的方法要传入 locator,这个方法直接传定位到的 element 就好了;
  • presence_of_all_elements_located:判断是否至少有1个元素存在于 dom 树中。举个例子,如果页面上有n个元素的 class 都是 'column-md-3',那么只要有1个元素存在,这个方法就返回 True;
  • text_to_be_present_in_element:判断某个元素中的 text 是否包含了预期的字符串;
  • text_to_be_present_in_element_value:判断某个元素中的 value 属性是否包含了预期的字符串;
  • frame_to_be_available_and_switch_to_it:判断该 frame 是否可以 switch 进去,如果可以的话,返回 True 并且 switch 进去,否则返回 False;
  • invisibility_of_element_located:判断某个元素中是否不存在于 dom 树或不可见;
  • element_to_be_clickable:判断某个元素中是否可见并且是 enable 的,这样的话才叫 clickable;
  • staleness_of:等某个元素从 dom 树中移除,注意,这个方法也是返回 True 或 False;
  • element_to_be_selected:判断某个元素是否被选中,一般用在下拉列表;
  • element_selection_state_to_be:判断某个元素选中状态是否符合预期;
  • element_located_selection_state_to_be:跟上面的方法作用一样,只是上面的方法传入定位到的 element,而这个方法传入 locator;
  • alert_is_present:判断页面上是否存在 alert。

最后

至此,爬虫入门的知识点也介绍完了,有了这些基础知识后,便可以进一步的进行爬虫实战了。后面将通过爬虫实战,演示如何灵活的爬取不同网站并解析出目标数据,并记录下爬取和解析过程中遇到的一些问题,一起期待吧~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

项目中如何配置 Maven 为国内源

目录 1. 创建出一个 Maven 项目 2. 打开项目配置界面, 检查并配置国内源 2.1 打开配置界面 (当前项目界面和新项目配置界面) 2.2 搜索 "Maven" 2.3 设置 setting.xml (给此 xml 中添加国内源) 2.4 把上面的步骤 (2.1~2.3) 在新项目的配置界面中重新配置一遍. …

【MySQL】MySQL事务隔离机制与实现原理详解(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

加权黑猩猩优化算法(WChOA)附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

Java实现五子棋(附源码)

文章目录一、游戏介绍二、效果展示三、代码展示1、登录页面2、算法程序3、棋盘实现四、资源下载五、文末总结一、游戏介绍 今天给大家分享一个用java写的小游戏——《五子棋》 &#xff08;完整代码可在【资源下载】目录查看&#xff09; 。五子棋是一种两人对弈的纯策略型棋类…

中缀表达式转后缀表达式

1 后缀表达式 一种不需要括号的表达式方法&#xff0c;也把它称为 逆波兰表达式&#xff0c;是波兰逻辑学家卢卡西维奇&#xff08;Lukasiewicz)发明的一种表示表达式的方法。 2 中缀表达式 中缀表达式也就是我们常见的表达式书写方法&#xff0c;比如“8(2-1)352”就是一个中…

HTML期末大作业——游戏介绍(HTML+CSS+JavaScript) web前端开发技术 web课程设计网页规划与设计 Web大学生网页成品

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

前端爱心代码跟个风

光棍节new一个对象发给Ta <!DOCTYPE html> <html><head><title></title> </head> <style>* {padding: 0;margin: 0;}html,body {height: 100%;padding: 0;margin: 0;background: rgb(2, 2, 2);}canvas {position: absolute;width: …

关于 SAP 电商云 Spartacus UI Navigation Service 执行的一些明细

第一次触发的时候&#xff0c;navigation.uid 并没有值&#xff1a; 下图&#xff1a;navigation.service 的 getNavigationNode 方法。 触发这个订阅的入口&#xff1a; <cx-navigation-ui*ngIf"data$ | async as data"[node]"node$ | async"[ngC…

【HTML实战】把爱心代码放在自己的网站上是一种什么体验?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【HTML】 最近随着电视剧《点燃我温暖你》的火热播出&#xff0c;剧中帅气学霸李洵的炫酷爱心代码也迅速火出了圈&#xf…

【毕业设计】口罩佩戴检测系统 - opencv 卷积神经网络 机器视觉 深度学习

文章目录&#x1f6a9; 0 简介&#x1f6a9;1 课题背景&#x1f6a9; 2 口罩佩戴算法实现2.1 YOLO 模型概览2.2 YOLOv32.3 YOLO 口罩佩戴检测实现2.4 实现代码2.5 检测效果&#x1f6a9; 3 口罩佩戴检测算法评价指标3.1 准确率&#xff08;Accuracy&#xff09;3.2 精确率(Prec…

Golang学习之路5-结构体/类封装等使用

文章目录前言一、结构体1.声明结构体2.匿名结构体二、类1.封装及绑定2.继承3.多态及接口4.类访问权限总结前言 go语言支持类的操作&#xff0c;但是没有class关键字&#xff0c;使用struct来模拟类、结构体。类支持封装、绑定方法、继承等 一、结构体 结构体是由零个或多个任…

【C++进阶】map和set( 万字详解)—— 上篇

&#x1f387;C学习历程&#xff1a;进阶 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

青少年python系列 42.面向对象-继承

青少年python系列目录_老程序员115的博客-CSDN博客 青少年python教学视频ppt源码 继承&#xff1f;继承啥&#xff1f;提起继承这两个字&#xff0c;最先能够联想到的应该就是子继父业这个成语。还记得之前在我们的课程中提及过&#xff0c;在面向对象编程时&#xff0c;是可以…

【Linux】关于进程的理解、状态、优先级和进程切换

文章目录&#x1f4dd;一、操作系统进程1.运行队列2.运行状态&#x1f4dd;二、Linux进程状态&#x1f4dd;三、两个特殊进程1.僵尸进程2.孤儿进程&#x1f4dd;四、进程优先级1.优先级概念2.查看系统进程3.PRI和NI4.top命令更改nice5.特性&#x1f4dd;五、进程切换1.并发2.进…

软件工程方法论

&#x1f430;作者简介&#xff1a;一位普通高校的在校学生&#xff0c;致力于提高自己的编程能力。 &#x1f34c;个人主页&#xff1a;比昨天强一點的博客_CSDN博客-C语言从0到精通领域博主 &#x1f34d;系列专栏&#xff1a;C语言从0到精通_比昨天强一點的博客-CSDN博客 &a…

真良心干货保姆级手把手教你Python网络编程,学不会我去你家教你

Python网络编程基本概念(计算机网络基础)IP地址与端口IP地址端口网络通信协议网络通信协议网络协议的分层TCP/UDP套接字编程socket()函数介绍UDP 编程实现UDP发送数据实现UDP先发送数据再接收数据实现UDP实现多线程聊天TFTP文件下载器基本概念下载的过程python内置模块structTC…

C/C++ Qt 标准Dialog对话框组件应用

在Qt中对话框分为两种形式&#xff0c;一种是标准对话框&#xff0c;另一种则是自定义对话框&#xff0c;在一般开发过程中标准对话框使用是最多的了&#xff0c;标准对话框一般包括 QMessageBox,QInputDialog,QFileDialog 这几种&#xff0c;这里我将总结本人在开发过程中常用…

蓝桥杯——2022年11月第十四届蓝桥杯模拟赛第一期Java

1、二进制位数 问题描述 十进制整数 2 在十进制中是 1 位数&#xff0c;在二进制中对应 10 &#xff0c;是 2 位数。 十进制整数 22 在十进制中是 2 位数&#xff0c;在二进制中对应 10110 &#xff0c;是 5 位数。 请问十进制整数 2022 在二进制中是几位数&#xff1f; 答案…

C++学习之旅 第二章 printf与cout

目录 1.printf简介 2.printf的四种用法 2.1 printf("字符串"); 2.2 printf("输出控制符",输出参数); 2.3 printf("输出控制符1 输出控制符2 ,,,,,,,, ", 输出参数1&#xff0c; 输出参数2&#xff0c;....... ); 2.4 printf("输出控制…

化妆品展示网页设计作业 静态HTML化妆品网站 DW美妆网站模板下载 大学生简单网页作品代码 个人网页制作 学生个人网页设计作业

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…