Python爬虫合集:花6k学习爬虫,终于知道爬虫能干嘛了

csdn i春秋作家:evi1ox前言首发先知:https://xz.aliyun.com/t/2320知识那么多,大佬们学慢点,我营养跟不上啦! 前人栽树后人乘凉,本文主要是把一些资料依葫芦画瓢学习了下,做了个汇总.0×00 小二上酒https://github.com/se55i0n/DBScannera)Redis未授权访问b)Jenkins未授权访问c)MongoDB未授权访问d)ZooKeeper... 阅读详情

爬虫Ⅰ:爬虫的基础知识

爬虫的基础知识使用实例、应用技巧、基本知识点总结和需要注意事项

爬虫初始:

爬虫:

+ Request
+ Scrapy

数据分析+机器学习

+ numpy,pandas,matplotlib

jupyter:

+ 启动:到你需要进去的文件夹,然后输入jupyter notebook

cell是分为不同模式的:(Code:编写代码、markdown:编写笔记)

jupyter的快捷键:

添加cell: a, b (a向前添加,b先后添加)

删除cell: x

执行:shift+enter(执行并且光标到下一行),ctrl+enter(执行并且光标仍然在这一行)

tab:自动补全切换cell的模式:

  1. m :makedown模式
  2. y:代码模式

打开帮助文档:shift + tab

爬虫简介(了解):

1、什么是爬虫?

通过编写程序模拟浏览器上网,然后让其去互联网上爬取数据的过程

2、爬虫的分类:

通用爬虫:抓取互联网中的一整张页面数据

聚焦爬虫:抓取页面中的局部数据

增量式爬虫:用来监测网站数据更新的情况,以便爬取到网站最新更新出来的数据

3、反爬机制

4、反反爬策略

5、爬虫合法吗?

5.1爬取数据的行为风险的体现:

爬虫干扰了被访问网站的正常运营;

爬虫抓取了受到法律保护的特定类型的数据或信息。

5.2规避风险:

严格遵守网站设置的robots协议;

在规避反爬虫措施的同时,需要优化自己的代码,避免干扰被访问网站的正常运行;

在使用、传播抓取到的信息时,应审查所抓取的内容,如发现属于用户的个人信息、隐私或者他人的商业秘密的,应及时停止并删除。

6、robots协议:

文本协议特性:防君子不防小人的文本协议

request模块的基本使用:

什么是requests模块?Python中封装好的一个基于网络请求的模块。

requests模块的作用?用来模拟浏览器发请求

requests模块的环境安装:pip install requests

requests模块的编码流程:指定url、发起请求、获取响应数据、持久化存储

爬取搜狗首页源码数据

import requests
# 1.指定url
url = 'https://www.sogou.com/'
# 2.请求发送get:get返回值是一个响应对象
response = requests.get(url=url)
# 3.获取响应数据
page_text = response.text    # 返回的是字符串形式的响应数据
# 4.持久化存储
with open('sogou.html',mode='w',encoding='utf-8') as fp:
    fp.write(page_text)

实现一个简易的网页采集器

第一版:

需要让url携带的参数动态化
import requests
url = 'https://www.sogou.com/web'
# 实现参数动态化
wd = input('enter a key:')
params = {
    'query': wd
}
# 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
response = requests.get(url=url, params=params)

page_text = response.text
file_name = wd+'.html'
with open(file_name,encoding='utf-8',mode='w') as fp:
    fp.write(page_text)

第二版:

  • 上述代码运行后发现:出现了乱码、数据量级不对
  • 解决乱码:解决响应数据的编码方式
import requests
url = 'https://www.sogou.com/web'
wd = input('enter a key')
params = {
    'query': wd
}
response = requests.get(url=url, params=params)
response.encoding = 'utf-8'
page_text = response.text
filename = wd + '.html'
with open(filename, mode='w', encoding='utf-8') as fp:
    fp.write(page_text)

第三版:(加一个headers,模拟浏览器登入)

  • UA检测:门户网站通过检测请求载体的身份标识判定该请求是否为爬虫发起的请求
  • UA伪装:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
import requests
url = 'https://www.sogou.com/web'
wd = input('enter a key')
params = {
    'query': wd
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}
response = requests.get(url=url, params=params, headers=headers)
response.encoding = 'utf-8'
page_text = response.text
filename = wd + '.html'
with open(filename, mode='w', encoding='utf-8') as fp:
    fp.write(page_text)

当网页发生局部刷新

  • 爬取的是豆瓣电影中电影的详情数据https://movie.douban.com/typerank?type_name=%E7%88%B1%E6%83%85&type=13&interval_id=100:90&action=
  • 分析:当滚动条被滑动到页面底部的时候,当前页面发生了局部刷新(ajax的请求)
动态加载的页面数据
是通过例一个单独的请求请求到的数据
import requests
url = 'https://movie.douban.com/j/chart/top_list'
start = input('电影开始')
end = input('电影结束')
dic = {
    'type': '13',
    'interval_id': '100:90',
    'action': '',
     'start': start,
     'end': end
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}
response = requests.get(url=url, params=dic, headers=headers)
page_text = response.json()    # json返回的是序列化好的实例对象
for dic in page_text:
    print(dic['title']+dic['score'])

请求为post是参数为data——肯德基案例

  • 肯德基餐厅查询http://www.kfc.com.cn/kfccda/storelist/index.aspx
  • 注意:get请求参数时params,但是post请求参数时data
import requests
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
site = input('请输入地点>>')
for page in range(1, 5):
    data = {
        'cname':'',
            'pid':'',
    'keyword': site,
    'pageIndex': '1',
    'pageSize': '10'
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
    }
    response = requests.post(url=url, data=data,headers=headers)
    print(response.json())

数据解析简介

数据解析

数据解析的作用:可以帮助我们实现聚焦爬虫

数据解析的实现方式:正则、bs4、xpath、pyquery

数据解析的通用原理:

1.爬虫爬取的数据都被存储在了相关的标签之中和相关标签的属性中

2.定位标签

3.取文本或者取属性

爬取byte类型数据

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
}

1.爬取byte类型数据(如何爬取图片)
url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg'
img_data = requests.get(url=url).content    # 爬取byte类使用.content
with open('./img.jpg',mode='wb') as fp:
    fp.write(img_data)


# 弊端:不能使用UA伪装
from urllib import request
# url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg'
# request.urlretrieve(url, filename='./qutu.jpg')

正则解析

  • 先用通用模板找到对应的网页,再用正则找到你所需要的内容
import os
import re
# 糗图爬取1-3页所有的图片
# 1.使用通用爬虫将前3页对应的页面源码数据进行爬取
# 通用的url模板(不可变)
1.创建目录
dirName = "./imgLibs"
if not os.path.exists(dirName):
    os.mkdir(dirName)
url = f"https://www.qiushibaike.com/imgrank/page/%d/"
# 2.下载图片
for page in range(1, 3):
    new_url = format(url%page)
    page_text = requests.get(url=new_url,headers=headers).text    # 每一个页码对应的源码数据
    ex = '<div class="thumb">.*?<img src="(.*?)".*?</div>'
    img_src_list = re.findall(ex, page_text, re.S)
    for src in img_src_list:
        src = "https:" + src
        img_name = src.split('/')[-1]
        img_path = dirName + '/' + img_name    #./imgLibs/xxxx.jpg
        request.urlretrieve(src, filename=img_path)
        print(img_name, '下载成功')

bs4解析

1.知识点:

bs4解析bs4解析的原理:

实例化一个BeautifulSoup的对象,需要将即将被解析的页面源码数据加载到该对象中

调用BeautifulSoup对象中的相关方法和属性进行标签定位和数据提取

环境的安装:

pip install bs4

pip install lxml

BeautifulSoup的实例化:

BeautifulSoup(fp,'lxml'):将本地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中

BeautifulSoup(page_text,'lxml'):将从互联网上获取的页面源码数据加载到实例化好的BeautifulSoup对象中

定位标签的操作:

soup.tagName:定位到第一个出现的tagName标签

属性定位:soup.find('tagName',attrName='value')

属性定位:soup.find_all('tagName',attrName='value'),返回值为列表

选择器定位:soup.select('选择器'),返回的是列表

      层级选择器:>表示一个层级 空格表示多个层级

取文本:

string:获取直系的文本内容

.text:获取所有的文本内容

取属性:

tagName['attrName']

2.代码示例:

定位标签
from bs4 import BeautifulSoup
fp = open('./test.html', mode='r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')

print(soup.div)    # 定位到第一个出现的div
find相关
print(soup.find('div', class_='song'))    # 只有class_标签需要带_
print(soup.find('a', id='feng'))
print(soup.find_all('div', class_='song'))    # 返回的是一个列表
select相关
print(soup.select('#feng'))    # 返回的是一个列表
print(soup.select('.tang > ul >li'))    # 返回的是一个列表 > 表示一个层级
print(soup.select('.tang li'))    # 返回一个列表  空格表示多个层级
取文本
a_tag = soup.select("#feng")[0]
print(a_tag.text)
div = soup.div
print(div.string)    # 取直系的文本内容
div = soup.find('div', class_='song')
print(div.string)
a_tag = soup.select('#feng')[0]
print(a_tag['href'])

3.具体案例:

爬取三国整篇内容(章节名称+章节内容)http://www.shicimingju.com/book/sanguoyanyi.html
fp = open('./sanguo.txt', mode='w', encoding='utf-8')
main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=main_url, headers=headers).text
soup1 = BeautifulSoup(page_text, 'lxml')
title_list = soup1.select('.book-mulu > ul > li > a')
for page in title_list:
    title = page.string
    title_url = 'https://www.shicimingju.com' + page['href']
    title_text = requests.get(url=title_url, headers=headers).text
    # 解析详情页中的章节内容
    soup = BeautifulSoup(title_text, 'lxml')
    content = soup.find('div', class_='chapter_content').text
    fp.write(title + ':' + content + '\n')
    print(f'{title}下载成功')

xpath解析

1. 知识点:

xpath解析的实现原理:

1.实例化一个etree的对象,然后将即将被解析的页面源码加载到该对象中

2.使用etree对象中的xpath方法结合着不同形式的xpath表达式实现标签定位和数据提取

环境安装:

pip install lxmletree

对象的实例化:

etree.parse('test.html') # 本地文件

etree.HTML(page_text) # 互联网页面

xpath表达式:xpath方法的返回值一定是一个列表

最左侧的/表示:xpath表达式一定要从根标签逐层进行标签查找和定位

最左侧的//表示:xpath表达式可以从任意位置定位标签

非最左侧的/:表示一个层级

非最左侧的//:表示跨多个层级

属性定位://tagName[@attrName="value"]

索引定位://tagName[index] 索引是从1开始

取文本:/text():直系文本内容//text():所有的文本内容

取属性:/@attrName

2.代码示例:

from lxml import etree
tree = etree.parse('./test.html')
标签定位
print(tree.xpath('/html/head/title'))
print(tree.xpath('//title'))
print(tree.xpath('/html/body//p'))
print(tree.xpath('//p'))
属性定位
print(tree.xpath('//div[@class="song"]'))
print(tree.xpath('//li[3]'))    # 返回的是一个对象地址
取文本
print(tree.xpath('//a[@id="feng"]/text()')[0])    # 返回的是列表
print(tree.xpath('//div[@class="song"]//text()'))    # 返回的是列表
取属性
print(tree.xpath('//a[@id="feng"]/@href'))    # 返回的是列表

3.具体案例:

#爬取糗百中的段子内容和作者名称
url = 'https://www.qiushibaike.com/text/'
page_text = requests.get(url,headers=headers).text

#解析内容
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@id="content-left"]/div')
for div in div_list:
    author = div.xpath('./div[1]/a[2]/h2/text()')[0]#实现局部解析
    content = div.xpath('./a[1]/div/span//text()')
    content = ''.join(content)
    
    print(author,content)

4.提高xpath通用性

https://www.aqistudy.cn/historydata/ 爬取所有城市名称
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
print(tree)
city_list1 = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
print(city_list1)
city_list2 = tree.xpath('//ul[@class="unstyled"]//li/a/text()')
print(city_list2)
利用|提高xpath的通用性(当前面表达式生效时执行前面,后面表达式生效时执行后面。两个同时生效时同时执行)
cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //ul[@class="unstyled"]//li/a/text()')
print(cities)

中文乱码的处理

#http://pic.netbian.com/4kmeinv/中文乱码的处理  
dirName = './meinvLibs'
if not os.path.exists(dirName):
    os.mkdir(dirName)
url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
for page in range(1,11):
    if page == 1:
        new_url = 'http://pic.netbian.com/4kmeinv/' 
    else:
        new_url = format(url%page)
    page_text = requests.get(new_url,headers=headers).text
    tree = etree.HTML(page_text)
    a_list = tree.xpath('//div[@class="slist"]/ul/li/a')
    for a in a_list:
        img_src = 'http://pic.netbian.com'+a.xpath('./img/@src')[0]
        img_name = a.xpath('./b/text()')[0]
        img_name = img_name.encode('iso-8859-1').decode('gbk')    # 对乱码部分进行编码解码
        img_data = requests.get(img_src,headers=headers).content
        imgPath = dirName+'/'+img_name+'.jpg'
        with open(imgPath,'wb') as fp:
            fp.write(img_data)
            print(img_name,'下载成功!!!')

代理

HttpConnectionPool:错误原因

  • 原因:短时间发起高频的请求导致ip被禁http连接池中的连接资源被消耗尽
  • 解决:代理headers中加入Conection: "close"

代理:代理服务器,可以接受请求然后将其转发

匿名度:

  • 高匿:啥也不知道
  • 匿名:知道你使用了代理,但是不知道你的真实ip
  • 透明:知道你使用了代理并且知道你的真实ip

类型:http、https

免费代理:www.goubanjia.com、快代理西

cookie的处理

使用代理的简单案例

import requests
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'Connection': 'close'
}
 # url = 'https://www.baidu.com/s?wd=ip'
 url = 'http://ip.chinaz.com/'
 page_text = requests.get(url=url, headers=headers, proxies={'http': '123.169.122.111:9999'}).text
 with open('./ip.html', mode='w', encoding='utf-8') as fp:
    fp.write(page_text)

代理池

代理池:构建自己的代理池

import random
proxy_list = {
    {'https': '121.231.94.44:8888'},
    {'https': '131.231.94.44:8888'},
    {'https': '141.231.94.44:8888'}
}
url = 'https://www.baidu.com/s?wd=ip'
page_text = requests.get(url=url, headers=headers, proxies=random.choice(proxy_list)).text
with open('ip.html', 'w', enconding='utf-8') as fp:
    fp.write(page_text)

从代理精灵中提取代理ip,为了获取一系列ip来构建自己的代理池

from lxml import etree
ip_url = 'http://t.11jsq.com/index.php/api/entry?method=proxyServer.generate_api_url&packid=1&fa=0&fetch_key=&groupid=0&qty=4&time=1&pro=&city=&port=1&format=html&ss=5&css=&dt=1&specialTxt=3&specialJson=&usertype=2'
page_text = requests.get(ip_url, headers=headers).text
tree = etree.HTML(page_text)
ip_list = tree.xpath('//body//text()')
print(ip_list)

第一步:爬取ip,port http类型

  • 爬取西祠代理(已挂)获取可用ip构建自己代理池
import random
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'Connection': "close"
}
# url = 'https://www.xicidaili.com/nn/%d'    # 西祠代理(已挂)
url = 'https://www.kuaidaili.com/free/inha/%d/'
proxy_list_http = []
proxy_list_https = []
for page in range(1, 20):
    new_url = format(url%page)
    ip_port = random.choice(ip_list)
    page_text = requests.get(new_url, headers=headers, proxies={'https': ip_port}).text
    tree = etree.HTML(page_text)
    # tbody不可以出现在xpath表达式中
    tr_list = tree.xpath('//*[@id="list"]/table//tr')[1:]    # 这里不能要tbody,索引是从1开始的
    for tr in tr_list:
        ip = tr.xpath('./td[1]/text()')[0]    # 返回的是一个列表
        port = tr.xpath('./td[2]/text()')[0]
        t_type = tr.xpath('/td[4]/text()')[0]
        ips = ip+":" + port
        if t_type == 'HTTP':
            dic = {
                t_type: ips
            }
            proxy_list_http.append(dic)
        else:
            dic = {
                t_type: ips
            }
            proxy_list_https.append(dic)
print(len(proxy_list_http), len(proxy_list_https))

第二步: 检测,将可用的ip留下来

for ip in proxy_list_http:
    response = requests.get('https://www/sogou.com', headers=headers,proxies={'https': ip})
    if response.status_code == '200':
        print('检测到了可用的ip')

cookie的处理

cookie的处理:

手动处理:将cookie封装到headers中

自动处理:session对象.可以创建一个session对象,该对象可以像requests一样进行请求发送;

不同之处在于如果在使用session进行请求发送的过程中产生了cookie,则cookie会被自动存储在session对象中

案例:对雪球网中的新闻数据进行爬取https://xueqiu.com/

手动

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'Cookie':'device_id=24700f9f1986800ab4fcc880530dd0ed; xq_a_token=db48cfe87b71562f38e03269b22f459d974aa8ae; xqat=db48cfe87b71562f38e03269b22f459d974aa8ae; xq_r_token=500b4e3d30d8b8237cdcf62998edbf723842f73a; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTYwNjk2MzA1MCwiY3RtIjoxNjA1NTM1Mjc2NzYxLCJjaWQiOiJkOWQwbjRBWnVwIn0.PhEaPnWolUZRgyuOY-QO04Bn_A_HYU46Hm54_kWBxa8IZ6cFw20trOr7rKp7XztprxEFc7fkMN2_5abfh1TUyyFKqTDn7IfoThXyJ2lJCnH33q1q-K9BclYvLHrLGqt8jQ3YOJi7-nyiSb5ZTNk7TLEhiFfsbXaZK9evNrt7W65MdxoEWyCcGjbhI5znffRxDDLHD9511bd9upY9CUGbf4SHQwwx4PxyQqdy9j5bgqPN6rsuHoCvjcr42DZYRd8B72uQTkFs-Lnru4AFxt4o4gdaxPo_Qd_IqzCrXnwoLtCdX6n4NKV44SryBttE0SKQC6UbqC35PwN-JqPeWCHKpQ; u=201605535281005; Hm_lvt_1db88642e346389874251b5a1eded6e3=1605354060,1605411081,1605535282; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1605535282'
}
params = {
    'status_id': '163425862',
    'page': '1',
    'size': '14'
}
url = 'https://xueqiu.com/statuses/reward/list_by_user.json?status_id=163425862&page=1&size=14'
page_text = requests.get(url=url, headers=headers, params=params).json()
print(page_text)

自动:将Cookie永久存储session

session = requests.Session()
session.get('https://xueqiu.com/', headers=headers)    # 自动处理cookie,将首页的cookie存储到session中,后面爬取其他页面时可以用到
url = 'https://xueqiu.com/statuses/reward/list_by_user.json?status_id=163425862&page=1&size=14'
page_text = session.get(url=url, headers=headers).json()
print(page_text)

验证码的识别

step1:超级鹰中的示例代码

import requests
from hashlib import md5

class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):    # 用户名,密码,和软件id
        self.username = username
        password =  password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()

step2:识别古诗文网中的验证码

def tranformImgData(imgPath, t_type):    # 验证码图片的地址和验证码的类型
    chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')    # 需要注册的超级鹰的用户名,密码,和软件id
    im = open(imgPath, 'rb').read()
    return chaojiying.PostPic(im, t_type)['pic_str']    # t_type为该图片的类型码
# 从古诗文网中爬取验证码的图片,将图片保存到本地,然后将图片送入到超级鹰中识别,最后返回识别结果
url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
page_text = requests.get(url, headers=headers).text
tree = etree.HTML(page_text)
img_src = 'https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0]    # 它返回的是一个列表
img_data = requests.get(img_src, headers=headers).content    # .content时爬取图片数据
with open('./code.jpg', 'wb') as fp:
    fp.write(img_data)
tranformImgData('./code.jpg', 1004)    # 将图片路径和图片类型输入进去,返回识别出来的码

step3:重要 模拟登入,目的是为了将cookie保存到session中

# 将上述产生的验证码进行模拟登入
s = requests.Session()
url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
page_text = s.get(url, headers=headers).text
tree = etree.HTML(page_text)
img_src = 'https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0]
img_data = s.get(img_src, headers=headers).content    # cookie的产生在发生验证码图片时产生,目的是:1.产生cookie,2:产生图片
with open('./code.jpg', 'wb') as fp:
    fp.write(img_data)

# 动态获取变化的参数
__VIEWSTATE = tree.xpath('//*[@id="__VIEWSTATE"]/@value')[0]
__VIEWSTATEGENERATOR = tree.xpath('//*[@id="__VIEWSTATEGENERATOR"]/@value')[0]
# 获取前面超级鹰获得的验证码(将图片识别出来)
code_text = tranformImgData('./code.jpg', 1004)
print(code_text)    # 观察是否正确
# 该login_url是点击登入按钮后出现的页面,为post请求
login_url = 'https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
data = {
    '__VIEWSTATE': __VIEWSTATE,
    '__VIEWSTATEGENERATOR': __VIEWSTATEGENERATOR,
    'from':'http://so.gushiwen.org/user/collect.aspx',
    'email': 'www.zhangbowudi@qq.com',
    'pwd': 'bobo328410948',
    'code': code_text,
    'denglu': '登录',
}
page_text = s.post(url=login_url, headers=headers, data=data).text
with open('login.html', mode='w', encoding='utf-8') as fp:
    fp.write(page_text)

单线程+多任务异步协程

协程:

在函数(特殊的函数)定义的时候,如果使用了async修饰的话,则该函数调用后会返回一个协程对象,并且函数内部的实现语句不会被立即执行

任务对象

任务对象就是对协程对象的进一步封装。任务对象高级的协程对象特殊的函数

任务对象时必须要注册到事件循环对象中

给任务对象绑定回调:爬虫的数据解析中

事件循环

当做是一个容器,容器中必须存放任务对象;

当启动事件循环对象后,则事件循环对象会对其内部存储任务对象进行异步的执行。

aiohttp:支持异步网络请求的模块

1.协程

import asyncio
def callback(task):#作为任务对象的回调函数
    print('i am callback and ',task.result())    # task.result()是接受特殊函数内部的返回值

async def test():
    print('i am test()')
    return 'bobo'

c = test()
# 封装了一个任务对象,就是对协程对象的进一步封装
task = asyncio.ensure_future(c)    # 封装一个任务对象
task.add_done_callback(callback)    # 给任务对象绑定回调
#创建一个事件循环的对象
loop = asyncio.get_event_loop()    # 创建事件循环对象
loop.run_until_complete(task)    # 将任务对象注册到事件循环对象中

2.多任务

import asyncio
import time
start = time.time()
#在特殊函数内部的实现中不可以出现不支持异步的模块代码
async def get_request(url):
    await asyncio.sleep(2)    # 如果使用time的模块的sleep则不支持异步
    print('下载成功:',url)

urls = [
    'www.1.com',
    'www.2.com'
]
tasks = []
for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)    # 创建任务对象
    # 多任务可以在这里绑定回调
    tasks.append(task)

loop = asyncio.get_event_loop()    # 创建事件循环对象
#注意:挂起操作需要手动处理,
loop.run_until_complete(asyncio.wait(tasks))    # 将多个任务 注册到事件循环对象,并启用(将任务挂起)
print(time.time()-start)

3.在爬虫中的应用

import requests
import aiohttp
import time
import asyncio
s = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay'
]

# async def get_request(url):
#     page_text = requests.get(url).text
#     return page_text

# 使用aiohttp进行获取请求,它支持异步,requests不支持异步
async def get_request(url):
   async with aiohttp.ClientSession() as s:
       async with await s.get(url=url) as response:    # 发送一个get请求,细节处理:每个前面加一个async,遇到阻塞的加await
           page_text = await response.text()
           print(page_text)
   return page_text
tasks = []
for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)    # 封装一个所任务对象
    tasks.append(task)

loop = asyncio.get_event_loop()    # 创建事件循环对象
loop.run_until_complete(asyncio.wait(tasks))    # 将多个任务 注册到事件循环对象,并启用(将任务挂起)
print(time.time()-s)

step4:

单线程+多任务异步协程总结:

import aiohttp
import asyncio
import time
from lxml import etree
start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom'
]

# 特殊的函数:请求发送和响应数据的捕获
# 细节:在每一个with前加上async,在每一个阻塞操作的前边加上await
async def get_request(url):
    async with aiohttp.ClientSession() as s:    # requests不能发送异步请求所以使用aiohttp
        # s.get(url, headers=headers, proxy="http://ip:port", params)
        async with await s.get(url) as response:
            page_text = await response.text()    # read()返回的是byte类型的数据
            return page_text

# 回调函数(普通函数)
def parse(task):
    page_text = task.result()
    tree = etree.HTML(page_text)
    parse_data = tree.xpath('//li/text()')
    print(parse_data)
# 多任务
tasks = []
for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)    # 封装一个任务对象
    task.add_done_callback(parse)    # 当任务对象执行完了之后才会回调
    tasks.append(task)

# 将多任务注册到事件循环当中
loop = asyncio.get_event_loop()    # 创建事件循环对象
loop.run_until_complete(asyncio.wait(tasks))    # 将任务对象注册到事件循环对象中,并开启事件循环对象,这里wait是挂起的意思

print(time.time()-start)

selenium模块

selenium模块在爬虫中的使用

概念:是一个基于浏览器自动化的模块

爬虫之间的关联:便捷的捕获到动态加载到的数据。(可见即可得),缺点是慢实现模拟登录

环境安装:pip install selenium

基本使用:准备好某一款浏览器的驱动程序+ 版本的映射关系,实例化某一款浏览器对象

selenium模块的基本操作:

from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://www.jd.com/')
sleep(1)
# 进行标签定位
search_input = bro.find_element_by_id('key')
search_input.send_keys('mac pro')

btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
btn.click()
sleep(2)

# 执行js
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
page_text = bro.page_source
print(page_text)
sleep(2)
bro.quit()

selenium爬取动态加载的数据

from selenium import webdriver
from time import sleep
from lxml import etree
bro = webdriver.Chrome(executable_path='chromedriver.exe')

bro.get('http://scxk.nmpa.gov.cn:81/xk/')
sleep(2)
page_text = bro.page_source
page_text_list = [page_text]

for i in range(3):
    bro.find_element_by_id('pageIto_next').click()    # 点击下一页
    sleep(2)
    page_text_list.append(bro.page_source)

for page_text in page_text_list:
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@id="gzlist"]/li')
    for li in li_list:
        title = li.xpath('./dl/@title')[0]
        num = li.xpath('./ol/@title')[0]
        print(title, num)

sleep(2)
bro.quit()

动作链

动作链:

一系列连续的动作在实现标签定位时,如果发现定位的标签是存在于iframe标签之中的,则在定位时必须执行一个固定的操作:bro.switch_to.frame('id')

如果里面还嵌套了iframe

from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains
bro = webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-example-draggable')
# 如果里面还嵌套了iframe
bro.switch_to.frame('iframeResult')

div_tag = bro.find_element_by_id('draggable')
print(div_tag)

# 拖动=点击+滑动
action = ActionChains(bro)
action.click_and_hold(div_tag)    # 点击中加滑动

for i in range(5):
    # perform让动作链立即执行
    action.move_by_offset(17, 5).perform()
    sleep(0.5)
action.release()    # 让action回收一下

sleep(3)
bro.quit()

12306模拟登入

# 模拟登入12306
from selenium import webdriver
from time import sleep
from PIL import Image
from selenium.webdriver import ActionChains
from Cjy import Chaojiying_Client
from selenium.webdriver import ActionChains
bro = webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://kyfw.12306.cn/otn/login/init')
sleep(5)
bro.save_screenshot('main.png')    # 这个截图对图片格式有要求需要为.png

code_img_tag = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')

location = code_img_tag.location
size = code_img_tag.size
print(location, type(location))
print(size)
#裁剪的区域范围
rangle = (int(location['x']),int(location['y']),int(location['x']+size['width']),int(location['y']+size['height']))

print(rangle)
# 裁剪图
i = Image.open('./main.png')
frame = i.crop(rangle)
frame.save('code.png')


def get_text(imgPath,imgType):
    chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')
    im = open(imgPath, 'rb').read()
    return chaojiying.PostPic(im, imgType)['pic_str']


#55,70|267,133 ==[[55,70],[33,66]]
result = get_text('./code.png',9004)
all_list = []
if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
print(all_list)
# action = ActionChains(bro)
for a in all_list:
    x = a[0]
    y = a[1]
    ActionChains(bro).move_to_element_with_offset(code_img_tag,x,y).click().perform()
    sleep(1)

bro.find_element_by_id('username').send_keys('123456')
sleep(1)
bro.find_element_by_id('password').send_keys('67890000000')
sleep(1)
bro.find_element_by_id('loginSub').click()

sleep(5)
bro.quit()

selenium的其他操作

简介:

无头浏览器的操作:无可视化界面的浏览器,PhantomJs:停止更新了

谷歌无头浏览器:让selenium规避检测,使用的是谷歌无头浏览器

from selenium import webdriver
from time import sleep

# 用到时直接粘贴复制
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 后面是你的浏览器驱动位置,记得前面加'r'是防止字符转义的
driver = webdriver.Chrome(r'chromedriver.exe', chrome_options=chrome_options)
driver.get('https://www.cnblogs.com/')
print(driver.page_source)
#如何规避selenium被检测
# 查看是否被规避掉,在console中输入window.navigator.webdriver,返回undefined则爬虫有效,返回True则被网站规避掉
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from time import sleep

# 用到时直接粘贴复制
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

driver = webdriver.Chrome(r'chromedriver.exe',options=option)
driver.get('https://www.taobao.com/')

 

自学Python爬虫简单入门到进阶(一):正则表达式+lxml+requests+Beautiful Soup+基础 网络爬虫(又被称为网页蜘蛛、网络机器人,在FOAF社区中,更经常地称为网页追逐者)是一种按照一定的规则,自动抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。 爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这些问题往往会困扰到学习爬虫的小伙伴。 今天给大家分享99篇【Python爬虫】相关精选学习资料,其中... 阅读详情

相关推荐

f_fs.c 初始化流程(进行中)

前言 之所以选择f_fs.c作为这系列的开始,因为usb在/driver/usb下面的内容实在太多太多,如果讲各种各样点会太分散了。所以决定切入点以实际使用为主,就是f_fs了,目前我了解这是做bulk裸传输使用的,具体的通信协议自己确定。 初始化部分 开始点从这个路径下说起, /drivers/usb/gadget/function/f_fs.c 然后f_fs.c第一个使用的是include/composite.h中的宏定义function #define DECLARE_USB_FUNCTION(_n

weixin_36406973的博客 1966

69.You are working on an instance started using the SPFILE. You want to move the Flash Recovery Area

69.You are working on an instance started using the SPFILE. You want to move the Flash Recovery Area of your database to a new location. You want the Flashback log files to be stored in the new location. Given below are the steps to accomplish the task in

dwj19830118的专栏 2万+

Adaboost入门教程——最通俗易懂的原理介绍(图文实例)

Adaboost入门教程——最通俗易懂的原理介绍(图文实例)

Max的杂物仓 11万+

C语言入门干货:多种系统的C环境设置和简易代码运行

C 环境设置 本地环境设置 如果您想要设置 C 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C 编译器。 文本编辑器 这将用于输入您的程序。文本编辑器包括 Windows Notepad、OS Edit command、Brief、Epsilon、EMACS 和 vim/vi。 文本编辑器的名称和版本在不同的操作系统上可能会有所不同。例如,Notepad 通常用于 Windows 操作系统上,vim/vi 可用于 Windows 和 Linux/UNIX 操作系统上。 通过编辑

Python6886的博客 486

TI LP87745-Q1汽车雷达PMIC评估:从硬件设计到性能测试全解析

在汽车电子和高级驾驶辅助系统(ADAS)中,电源管理单元(PMIC)是确保传感器稳定可靠运行的核心。其工作原理在于集成多路高效电源转换器(如Buck、Boost)和精密监控电路,通过数字接口实现灵活配置与实时诊断。这项技术的核心价值在于为毫米波雷达等关键负载提供低噪声、高精度、满足严格时序与功能安全(ASIL)要求的供电方案,从而提升整个感知系统的信噪比与可靠性。其典型应用场景包括自动驾驶域控制器、车载传感器融合模块等。本文以德州仪器(TI)的LP87745-Q1专用PMIC及其评估模块(EVM)为例,深入

weixin_27017211的博客 309

淘晶驰串口屏自定义协议实战:5分钟搞定苹果时钟通信(附完整代码)

本文详细介绍了如何使用淘晶驰串口屏自定义通信协议快速实现苹果风格时钟的通信功能。通过精简的协议设计和完整的代码示例,开发者可以在5分钟内完成从硬件连接到软件实现的整个过程,适用于嵌入式开发中的高效通信需求。

weixin_29184371的博客 323

TowardsDataScience 博客中文翻译 2022(四十二)

在的一篇新论文(Hoffmann 等人的《训练计算优化大型语言模型》)中,DeepMind 的研究人员重新审视了 Kaplan 的结论,发现缩放训练令牌的数量(即模型输入的文本数据量)与缩放模型大小一样重要。给定固定的计算预算,研究人员应该以类似的比例分配预算,以增加模型大小和训练令牌的数量,从而达到计算最佳模型(通过最小训练损失来衡量)。"模型大小每增加一倍,训练标记的数量也应该增加一倍."这意味着,如果在数量明显更多的令牌上进行训练,较小的模型可以大大优于较大但次优的模型。他们证明了这一点。

龙哥盟 1423

【OpenClaw企业级智能体实战】第13篇:1+N架构实战!OpenClaw多Agent数字员工军团搭建指南(含完整配置+路由策略+代码落地)

单Agent因“记忆负担重、Token消耗高、响应不精准”已难以满足复杂场景需求,而多Agent团队通过“1个编排者+N个执行者”的分工协作模式,能让效率提升300%以上。本文基于OpenClaw 2026稳定版,结合阿里云开发者社区实战案例,从核心认知、准备工作、实操流程、协作机制、安全配置五大维度,完整拆解多Agent团队搭建全流程。文中包含可直接复制执行的代码、详细配置模板、路由策略设置及常见问题排查,新手可在1-2小时内落地属于自己的“数字员工”军团,覆盖内容创作、技术支持、多平台运营等多场景。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 745

Angular 应用架构指南(三)

我们刚刚完成了最后一章,本章让我们更多地了解了有哪些操作符以及如何有效地利用它们。有了这些知识,我们现在将更深入地探讨这个主题。我们将从了解存在哪些部分,到真正理解 RxJS 的本质。了解 RxJS 的本质涉及到了解是什么让它运转。为了揭示这一点,我们需要涵盖诸如热、温、冷观测量之间的区别;了解主题及其用途;以及有时被忽视的主题——调度器。我们还想要涵盖与 Observable 一起工作的其他方面,特别是如何处理错误以及如何测试您的观测量。在本章中,您将了解以下内容:热观测量、冷观测量和温观测量主题:它们与

龙哥盟 557

安装Openclaw[本地自动化AI助手]至windows【WSL2模式】系统 Openclaw for Windows

摘要:OpenClaw最佳兼容OpenAI系列模型,推荐使用ChatGPT API(需Auth鉴权),避免K*mi等模型导致的信用卡风险。Windows系统需满足WSL2支持条件(Win11或Win10 1903+版本)。安装需导入自签名根证书或跳过浏览器安全警告,通过离线包部署WSL发行版。使用时通过clawtoken命令获取网关认证令牌,并在浏览器完成设备配对。提供代购ChatGPT Plus账号服务(¥140/月),详细操作指南需加微信群获取文件。(150字)

qq_27246521的博客 455

以阿克曼转向车为例对URDF和XACRO文件进行解读

   最近我在古月学院购买了在Gazebo中实现阿克曼转向车的仿真课程,课程资料的阿克曼小车的XACRO文件在Gazebo里加载的时候报了三个错误,在这之前,我没接触过URDF或XACRO文件,本篇文章就以这个阿克曼小车的XACRO文件为例,对URDF或XACRO文件的格式和内容进行解读,期望经过解读和学习,找到错误原因及所在,并解决这三个错误    先来放一下上面右图所示的模型的完整的XACRO文件: <?xml version="1.0"?> <!-- racecar.urdf.x

慕羽★的博客 3700

69节入门python_Python爬虫合集:花6k学习爬虫,终于知道爬虫能干嘛了

爬虫Ⅰ:爬虫的基础知识爬虫的基础知识使用实例、应用技巧、基本知识点总结和需要注意事项爬虫初始:爬虫:+ Request+ Scrapy数据分析+机器学习+ numpy,pandas,matplotlibjupyter:+ 启动:到你需要进去的文件夹,然后输入jupyter notebookcell是分为不同模式的:(Code:编写代码、markdown:编写笔记)jupyter的快捷键:添加cel...

weixin_39954889的博客 1151

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

一篇看懂什么是网络爬虫

众所周知,信息时代每秒钟产生的数据是巨大的,在巨大的数据中一定会有相关的或有价值的数据,而Python网络爬虫可以找到这些有价值的数据。Python网络爬虫只是它的一个统称,其实质是挖掘网络上的海量数据,即在此基础上获取数据,对获取的数据进行分析,同时利用获取的数据和数据分析的结果,达到提高流量的目的,或者带来更多的流量。当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

m0_59236127的博客 428

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Python 爬虫从入门到放弃(11 个有趣的 Python 爬虫例子)_python网络爬虫例子

作为一个IT的过来人,我自己整理了一些python学习资料,都是别人分享给我的,希望对你们有帮助。学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】。

2401_87361769的博客 1143

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

什么是网络爬虫?有什么用?怎么爬?终于有人讲明白了

随着大数据时代的来临,网络爬虫在互联网中的地位将越来越重要。互联网中的数据是海量的,如何自动高效地获取互联网中我们感兴趣的信息并为我们所用是一个重要的问题,而爬虫技术就是为了解决这些问题而生的。我们感兴趣的信息分为不同的类型:如果只是做搜索引擎,那么感兴趣的信息就是互联网中尽可能多的高质量网页;如果要获取某一垂直领域的数据或者有明确的检索需求,那么感兴趣的信息就是根据我们的检索和需求所定位的这些信息,此时,需要过滤掉一些无用信息。前者我们称为通用网络爬虫,后者我们称为聚焦网络爬虫。

Yuki1127918的博客 533

Python 到底能干嘛?—次学会Python所有开发技能_学python能干嘛,需要全学吗

作为一个IT的过来人,我自己整理了一些python学习资料,希望对你们有帮助。学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】。

2401_84538544的博客 792

Python爬虫篇:爬虫笔记合集

Host:链接的主机Referer:来源、防盗链接, 类似想我们现在的行程码你是从来个地方来的User-Agent:用户代理,浏览器的身份标识,可以理解为你的身份证那么这些东西都是我们在发送请求需要带上证明自己身份的东西。

zxfbhxgnc的博客 2175

python可以用来干嘛?很多小伙伴一定很好奇,我来为大家解答。

在今天的互联网时代,python一词已经并不陌生了,它在很多地方都会用到,对于求职者来说,也是一个高薪的行业,那么,Python这个语言又可以用来干嘛呢??

WANGJUNAIJIAO的博客 96

python爬虫入门,10分钟就够了,这可能是我见过最简单的基础教学

爬虫的全称为网络爬虫,简称爬虫,别名有网络机器人,网络蜘蛛等等。网络爬虫是一种自动获取网页内容的程序,为搜索引擎提供了重要的数据支撑。搜索引擎通过网络爬虫技术,将互联网中丰富的网页信息保存到本地,形成镜像备份。我们熟悉的谷歌、百度本质上也可理解为一种爬虫。如果形象地理解,爬虫就如同一只机器蜘蛛,它的基本操作就是模拟人的行为去各个网站抓取数据或返回数据。① Python所有方向的学习路线图,清楚各个方向要学什么东西② 600多节Python课程视频,涵盖必备基础、爬虫和数据分析。

xiangxueerfei的博客 1621

python入门—进阶—爬虫—算法,很好的四本书籍附学习教程

python入门—进阶—爬虫—算法,很好的四本书籍附学习教程

隔壁王叔的博客 771

Python爬虫项目70例,附源码 70个Python爬虫练手实例

今天博主给大家带来了一份大礼,Python爬虫70例!!!以及完整的项目源码!!! 本文下面所有的爬虫项目都有详细的配套教程以及源码,都已经打包好上传到百度云了,链接在文章结尾处! 扫码此处领取大家自行获取即可~~~

m0_59162248的博客 6787
上一篇: Python进阶干货:[中文编码乱码]:案例及解决方法
下一篇: 真香!Python开发工程师都选择这个数据库:因为它免费?
土豆编程
博客等级 码龄6年 105粉丝 117原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值