在初学的爬虫过程中,很多人还不知道有些字段是如何生成的,怎样模拟生成这些字段来拼接头部。为了再次纪念【宏彦获水】成语初次面世,特地用【百度登陆】写下一篇登陆百度的教程,以供大家参考。

前面学习了如何在 get 的时候想服务器发送多变的请求数据,从而达到搜索的效果,而实际上 搜索是简单的登陆 !所以本文将要介绍如何向百度服务器发送 post 数据,从而达到模拟登陆百度的效果。

  1. 首先打开 firefox 浏览器,清除网页所有的历史纪录,这是为了防止以前的 Cookie 影响服务器返回的数据。
  2. F12 打开 firebug ,进入百度首页,点击 网络 -> 清除 ,这是为了删掉打开百度首页而弹出来的 html,方便后面的查找 html 数据。
  3. 点击登陆按钮,依次填写账号、密码、验证码,点击 登陆 ,在 firebug 中点击 保持 ,这是为了防止登陆成功后,登陆表单的 html 被清除。

firebug 中,找到如下一行 POST?login

点击前面的 + 号 -> post ,可以看到提交的表单,这个就是点击登陆后,网页向百度服务器后端发送的 登陆请求表单,表单中包含了 账号密码其他 等信息:

如果百度后台认为此 登陆表单请求 是正确的后,会在 头信息 -> 响应头信息 中返回一个 Set-Cookie 。当我们登陆成功后,关闭浏览器,下次再打开浏览器的时候发现百度还是处于一种登陆的状态,这就是和 Cookie 有关。在百度登陆成功后会返回一个 Cookie 储存到浏览器中,下次再打开百度的时候,浏览器中的 头信息 -> 请求头信息 中会携带一个 Cookie ,这个 Cookie 就是百度服务器判断你以前是否登陆过百度。而这个 Cooike 就是 Set-Cookie 加工而来的!那么重点来了,如果要用代码模拟登陆百度,应该要具备以下几个步骤:

  1. 构造请求表单
  2. 请求成功后获取 Cookie (这个 Cookie 并非 Set-Cookie)
  3. 在请求头部 header 中携带这个 Cookie ,就可以以登陆过后的身份访问百度

原理讲清楚了,那么下面开始实践!

构造请求表单

在上面的 POST?login 中发现百度的请求表单还是挺多的,那么如何表单中判断哪些是变化的那些事不变的?再一次清空 firefox 的全部历史纪录,清除 firebughtml ,重新在百度首页点击 登陆 ,填写 账号错误的密码验证码,复制 POST?login 中的 post 信息下来,然后重复前面的步骤,就可以得到很多 post 信息,拿出来对比就可以知道哪些信息是变化的了。这里要解释一下为什么要填写 错误的密码,因为密码错误啦,登陆框就会一直都在啊,免去了清除 全部历史纪录 和清除 html 的步骤。最后对比的情况如下:

可以发现,请求的表单有

staticpage
charset
token
tpl
subpro
apiver
tt
codestring
safeflg
u
isPhone
detect
gid
quick_user
logintype
logLoginType
idc
loginmerge
splogin
username
password
verifycode
mem_pass
rsakey
crypttype
ppui_logintime
countrycode
fp_uid
fp_info
loginversion
ds
tk
dv
traceid
callback

其中,被红框框起来的表单是多次请求变化的:

callback
tt
token
ppui_logintime
rsakey
verifycode

dstk 在第一次请求网页直接生成了:

https://passport.baidu.com/viewlog?ak=1e3f2dd1c81f2075171a547893391274&as=74a154e4&fs=MEBGsUNpNVBMjs8Tdudr8aAjW%2BFklVpfnDnMkmxZ3DMXZisUPveYoxrXH2HKd5pgidlfhvibzXjlMLk28ZUvrUpDazz2aivj1lT0DHKRrMLZBBvYrMBdY%2BenNlaoF8h%2F8s18t0DQtONJZoRMOt%2FDotooaXA1bPuODU3XkP5iOBv9GpK6mApUn2xQXIpSEFTInDKJEiFBfC04IfPyCVCe766QJT%2FS4CHeqIJsjVLa7aoNnh3%2BHSdvRx1Uay1Fy60q%2Fkz5TJ%2B8Ib25o8yDfFBcOdbIdhVwmDHp3R87v3%2BY0M9rl2MUlr4ZJO2vn98yspz9t60LrqhUsObz7FZIdG9sWRP6JNt00%2BeQIY6Z7liRZI75mSRTWGDHYMT8LU7KdOELrxdrM7OfHfoD%2BlJ8PpCPFPT8dOgJUKGwa0tkL6t5UKpOUUXoxbx3lkRUNSj5NxdNcRt3YZbDShJmXnRbfza7yDpgvzKBRULis%2BzxhbBijS5onMCPOB59OVGE6lges8nr9xhi0ZNM9f96V7S4elo4fsXUgQzmJJwsM69ah0RSVNFQbBNoGszbT47%2BHDORP%2Fd7OLGOeG8D9i5tMIf%2BYRgN6ing5B5lLpn5nn3KtshIWiAwrR5mijWZai7uheFiE2cHCovVBRAlfCp3yDtKRWN4cE55F9b0wvoDHSJmHqlVKp1%2BgbE9b1oUFmqOGWcWMakVQfrEFg6phufPuuaQLLdtX3%2Bir7yeC8rx8tHdcTz6CtJsWtVcavFV8Q8j8Ta90bSKp%2BjQlmOXmct7PeM3tRM8%2B946o67jwNX7CP1EjKw%2FYk5lP%2BmCqNjwK3eZf46pQGLmZYUOLuGBK73HeCPAlj4YlEfGrZYpCuLp1vthWK%2B5oZZR9c%2BLpu1aOGotEqebe2N6UaKbXhC2qn6h3glylAV%2B2HfY4wut%2Bj%2Frr3iJEhWLj7J7qD0fr5ojR993ru8qrZSxKYu1f5W6NhdGPz7ZpWRfBrIaxtMjliEgdrIZ82RSe930OeXJaXMzytvoxvsZaUYvODivXMsPXDlnEQ%2FiZPPAO1B3F06Y8so67piru9hrXdkBwGLP6G07wo2dCMPvSFHHuLSvFYWduRFscftm3qJ1XUSDHDYIe8t5y5ClLJJd%2FCAkdlhQc3iOQJUgOXp4tAjoSkkiLnramq%2BIa6ycbi%2BcfzE6recOWVsuTFC4rX0t4RLdY5yf%2BRkED6qYcR8LLorK0dVKTX34rRsvLFElzgbi%2FW1%2Fq8y8tU9X%2F3pQXzHEsw28si6pjHvbPd4rJoQTIoI5asbCbxKqjRCJCfJPXRbUxo%2BZeWwik4F5UiTzwpas3pQ%3D&callback=jsonpCallbackb5819&v=4646

直接返回结果 json,所以得到 dstk:

jsonpCallbackb5819({"code":0,"data":{"tk":"1966\/wzQ9fSm481E1Dd6MPpdaM08fX2AB5MkNq1aMZHDBoekhU51\/8+yOdlYGlLXJVKpduaYRnOVNhfERmTiBXB1Vw==","as":"a82478bc","ds":"oLZa10fYIvKavmDHTaWvTF5D9f3NBzweejdgFGUJB9yI6TFVGHZ8EtWhXcLshwfDL0sU7ymlQe3uVByWIXCym03HZTZxZmGaXl8Jw+unuO5D3SN29KiMO0oj1fSH58BU"}})

其中很明显可以看出来的是:

  1. tt 时间戳
  2. verifycode 验证码

那么就剩下几个请求表单还暂时无法得知,首先查找 callback

>1. 在 `firebug` 中勾选脚本,点击 `{}`
>2. 搜索中勾选 **多个文件**
>3. 在搜索框中搜索 `callback`

一直搜索,最后发现 callbackgetUniqueId 的生成有关:

那么换着 getUniqueId 来搜索,得到如下 javascrip 代码:

e.getUniqueId = function (e) {
return e + Math.floor(2147483648 * Math.random()).toString(36)
},

和上面的 JavaScrip 整理起来,那么 callback 的生成代码为:

function callback(){
return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36)
}

找到 callback 后,接下来要去寻找 token 。在 firebug 中寻找 token 第一次在哪里出现。最后发现首次出现在网址:

https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&tt=1495185331704&class=login&gid=63F95D8-F402-4128-A98B-C7D3C19B8F89&logintype=dialogLogin&callback=bd__cbs__3cagws

这个网址返回的是一个 Json

bd__cbs__3cagws({"errInfo": {"no": "0"},
"data": {"rememberedUserName": "", "codeString": "", "token": "6245a75e6ba48d39033a8c31dfcb37c7",
"cookie": "1", "usernametype": "", "spLogin": "rate", "disable": "",
"loginrecord": {'email': [], 'phone': []}}})

第一次 token 出现的地方找到了,那么分析一下请求出 token 的网址,网址中涉及到的变量有:

tpl
apiver
tt
class
gid
logintype
callback

为了查看哪些变量是变化的,就再次进行多次登陆。最后发现,变化的是:

tt
gid
callback

其中 tt 为长时间戳, callback 在前面已经找到并且能生成了,那么只剩下 gid 这个变量。老规矩,按照下面的步骤再去找出 gid

  1. firebug 中勾选脚本,点击 {}
  2. 搜索中勾选 多个文件
  3. 在搜索框中搜索 gid

搜索发现 gid 是由 gid: e.guideRandom 这个函数生成的:

那么接着搜搜这个函数 guideRandom ,找到如下 JavaScrip 代码:

this.guideRandom = function () {
return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) {
var t = 16 * Math.random() | 0,
n = 'x' == e ? t : 3 & t | 8;
return n.toString(16)
}).toUpperCase()
}(),

整理一下让其可以在 python 中运行:

function gid(){
return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) {
var t = 16 * Math.random() | 0,
n = 'x' == e ? t : 3 & t | 8;
return n.toString(16)
}).toUpperCase()
}

这样,根据 gidcallback 就能得到 token 了!

下面继续寻找 ppui_logintime ,按照规矩来:

  1. firebug 中勾选脚本,点击 {}
  2. 搜索中勾选 多个文件
  3. 在搜索框中搜索 ppui_logintime ,找到了 timeSpan: 'ppui_logintime'

接着搜索 timeSpan ,得到如下信息:

s.timeSpan = (new Date).getTime() - e.initTime

现在还是看不出什么东西,那么就继续搜索 initTime ,得到如下代码:

_initApi: function (e) {
var t = this;
t.initialized = !0,
t.initTime = (new Date).getTime(),
passport.data.getApiInfo({
apiType: 'login',
gid: t.guideRandom || '',
loginType: t.config && t.config.diaPassLogin ? 'dialogLogin' : 'basicLogin'
}).success(function (n) {
var i = t.fireEvent('getApiInfo', {
rsp: n
});

继续查找 initApi ,找到位置:

原来是在登陆的时候发生点击,内容改变,按键按下等事件的时候,会调用 _initApi,再看源码和 ppui_logintime 的数值可以发现, ppui_logintime 代表的是从输入信息开始到点击登陆后结束的时间差!那么在后面 post 的时候直接可以自己构造这个数据了。

那么最后还剩下一个变量 rsakey ,在查找网页的时候发现第一次出现 rsakey 的地方是:

https://passport.baidu.com/v2/getpublickey?token=fcd1f6684072372c6812a44c1d94bf51&tpl=mn&apiver=v3&tt=1461222170065&gid=C539A37-9B0C-4538-9920-E150AC6AE0D5&callback=bd__cbs__tpdrlq

也就是这里面的 key ,虽然名字不一样,但是值是一样的:

bd__cbs__tpdrlq({"errno": '0', "msg": '',
"pubkey": '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiA2HxDW2iVnunx7faCBG3YGBy\nvvF+ysFAIXIVjFTseU7x\/f+Gpr1VTWe2Kxc2dlzBkn5NuRHVxbyXCawu0QlMUfb8\nI2ukM1cIlL0e+B1nBnIp03oXjFvQNhIu58SI6vCoihWX6Qwhb6ZOvJdA249zCNBU\nlTyd7RVwgwaAthI6gQIDAQAB\n-----END PUBLIC KEY-----\n',
"key": 'wS27H0665CWXK64i2VP02AYtjQUTujkb'})

分析一下这个网址,出现的变量有:

token
tpl
apiver
tt
gid
callback

这些变量在前面都能找到,所以也就是说,根据 gidcallbacktoken 就能得到 rsakey 了!

下面开始讲解怎么用 python 来实现模拟百度登陆!首先需要构造一个持续登陆的链接,持续登陆的链接能够一直自我保存打开网页或者登陆后留下的 cookie ,当然这是存放在内存中的,例如:

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"}

session = requests.session()
session.get("https://passport.baidu.com/v2/?login", headers=headers)

session 就是一个持续的链接,一般用 python 访问网页是这样子调用的 requests.get ,这样子的访问不会保存历史访问留下的 cookie ,而用 session.get 能持续保存 cookie ,只要后面访问都用 session.get 或者 session.post 即可。

获取callback

callback 是由 JavaScrip 生成的:

function callback(){
return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36)
}

所以直接在 python 中运行这个 JavaScrip 就行了。 python 运行 JavaScrip 需要安装库 pyexecjs,在命令指示符下直接输入 pip3 install pyexecjs 即可。调用方式为:

import execjs
js = '''function callback(){
return 'bd__cbs__'+Math.floor(2147483648 * Math.random()).toString(36)
}
'''
ctx = execjs.compile(js)
callback = ctx.call("callback")

获取traceid

traceid 同样是可以用 JavaScrip 生成的,直接调用即可:

import execjs
js = '''function traceid(){
var e = {a: 1, b: 1, c: 1}
e.traceID = {
headID: e.traceID && e.traceID.headID || "",
flowID: e.traceID && e.traceID.flowID || "",
cases: e.traceID && e.traceID.cases || "",
initTraceID: function(e) {
var t = this;
e && e.length > 0 ? (t.headID = e.slice(0, 6),
t.flowID = e.slice(6, 8)) : t.destory()
},
createTraceID: function() {
var e = this;
return e.headID + e.flowID + e.cases
},
startFlow: function(e) {
var t = this
, n = t.getFlowID(e);
0 === t.flowID.length || t.flowID === n ? (t.createHeadID(),
t.flowID = n) : t.finishFlow(n)
},
finishFlow: function() {
var e = this;
e.destory()
},
getRandom: function() {
return parseInt(90 * Math.random() + 10, 10)
},
createHeadID: function() {
var e = this
, t = (new Date).getTime() + e.getRandom().toString()
, n = Number(t).toString(16)
, i = n.length
, s = n.slice(i - 6, i).toUpperCase();
e.headID = s
},
getTraceID: function(e) {
var t = this
, n = e && e.traceid || "";
t.initTraceID(n)
},
getFlowID: function(e) {
var t = {
login: "01",
reg: "02"
};
return t[e]
},
setData: function(e) {
var t = this;
return e.data ? e.data.traceid = t.createTraceID() : e.url = e.url + (e.url.indexOf("?") > -1 ? "&" : "?") + "traceid=" + t.createTraceID(),
e
},
destory: function() {
var e = this;
e.headID = "",
e.flowID = ""
}
};
e.traceID.initTraceID()
e.traceID.createHeadID() return e.traceID.createTraceID() + "01"
}'''
ctx = execjs.compile(js)
traceid = ctx.call("traceid")

获取gid

gid 同样是可以用 JavaScrip 生成的,直接调用即可:

import execjs
js = '''function gid(){
return 'xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) {
var t = 16 * Math.random() | 0,
n = 'x' == e ? t : 3 & t | 8;
return n.toString(16)
}).toUpperCase()
}'''
ctx = execjs.compile(js)
gid = ctx.call("gid")

获取时间tt

时间 tt 是一个毫秒级别的长时间,而 python 生成的时间戳是短时间,所以要在短时间戳后面加上毫秒的长度即可,这里处理的方法是:在短时间戳的后面加上 3 位数的随机数,从而构造出长时间戳。

import time
import random timerandom = random.randint(100, 999)
nowtime = int(time.time())
tt = str(nowtime) + str(timerandom)

获取token

有了 callbackgidtt 后,可以获取到 token ,构造请求参数:

tokendata = {
"tpl": "pp",
"subpro": "",
"apiver": "v3",
"tt": tt,
"class": "login",
"gid": gid,
"logintype": "basicLogin",
"callback": callback
}

更新头部,携带头部访问:

headers.update(dict(Referer="http://passport.baidu.com/", Accept="*/*", Connection="keep-alive", Host="passport.baidu.com"))
resp = session.get(url="https://passport.baidu.com/v2/api/?getapi", params=tokendata, headers=headers)

顺利抓到包含 token 的返回值,将其放到字典里面即可:

data = json.loads(re.search(r".*?\((.*)\)", resp.text).group(1).replace(""", """))
token = data.get('data').get('token')

顺利返回 token

获取rsakey

获取 rsakey 只需要构造如下请求参数即可:

tt = get_tt()
get_data = {
"token": token,
"tpl": "pp",
"subpro": "",
"apiver": "v3",
"tt": tt,
"gid": gid,
"callback": callback,
}

在得到的返回值中提取出 rsakeypubkey 既可:

tt = get_tt()
rsakeydata = {
"token": token,
"tpl": "pp",
"subpro": "",
"apiver": "v3",
"tt": tt,
"gid": gid,
"callback": callback,
}
resp = session.get(url="https://passport.baidu.com/v2/getpublickey", headers=headers, params=rsakeydata)
data = json.loads(re.search(r".*?\((.*)\)", resp.text).group(1).replace("'", '"')) dicts = {}
dicts["rsakey"] = data.get("key")
dicts["pubkey"] = data.get("pubkey")

加密密码

百度登陆的密码加密方式是很简单的 RSA 加密,这个只是用 JavaScrip 就能实现,翻译成 python 的代码为:

def base64_password(password, pubkey):
pub = rsa.PublicKey.load_pkcs1_openssl_pem(pubkey.encode("utf-8"))
encript_passwd = rsa.encrypt(password.encode("utf-8"), pub)
return base64.b64encode(encript_passwd).decode("utf-8")

需要安装库 rsa ,只需要在命令指示符下输入:

pip3 install rsa

登陆

构造一个登陆的 postdata

post_data = {
"staticpage": "https://passport.baidu.com/static/passpc-account/html/v3Jump.html",
"charset": "utf-8",
"token": token,
"tpl": "pp",
"subpro": "",
"apiver": "v3",
"tt": tt,
"codestring": "",
"safeflg": 0,
"u": "http://passport.baidu.com/disk/home",
"isPhone": "",
"detect": 1,
"gid": gid,
"quick_user": 0,
"logintype": "basicLogin",
"logLoginType": "pc_loginBasic",
"idc": "",
"loginmerge": "true",
"foreignusername": "",
"username": username,
"password": newpassword,
"mem_pass": "on",
# 返回的key
"rsakey": rsakey,
"crypttype": 12,
"ppui_logintime": 33554,
"countrycode": "",
"dv": dv,
"callback": "parent." + callback
}

直接登陆:

resp = session.post(url="https://passport.baidu.com/v2/api/?login", data=post_data, headers=headers)

如果检测到自己在账号包含在返回的 html 里面,则说明登陆成功:

if username in resp.content.decode("utf-8", "ignore"):
print("登录成功")
else:
print("登录失败")

登陆成功后有两种方式在登陆状态下访问网页:

  1. 持续使用 session
  2. 获取登录后的 cookie

第一种方法在本次程序跑完后就会自动将后台保存下来的 cookie 丢弃掉,如果下次需要访问则需要重新登陆;第二种方法只要在头部增加这个 cookie 值,就能一直使用 cookie 保证是登陆状态,获取登录后的 cookie 的方法为:

cookies = requests.utils.dict_from_cookiejar(session.cookies)
print(cookies)

等到的 cookies 为一个字典,将这个字典保存在本地的 json 中:

import json
file = open("cookie.json","w")
file.write(json.dumps(cookies))
file.close()

下次访问携带这个 cookies 即可:

json_file = open("cookie.json")
cookies = json.load(json_file)
json_file.close() header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0',
'Host': 'passport.baidu.com',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',
'Connection': 'keep-alive'} home_page = requests.get("https://passport.baidu.com/center", headers=headers,cookies=cookies).content.decode("utf-8", "ignore")
print(home_page)

这里需要提醒的是 cookie 会过期,一般是 7 天,如果发现使用 cookie 登陆失败,那么就需要重新使用账号密码登陆获取 cookie

欢迎关注公众号【 机器学习和大数据挖掘 】,联系作者以及获取最新资讯

爬虫之抓js教程的更多相关文章

  1. NET 5 爬虫框架/抓取数据

    爬虫大家或多或少的都应该接触过的,爬虫有风险,抓数需谨慎.  爬虫有的是抓请求,有的是抓网页再解析 本着研究学习的目的,记录一下在 .NET Core 下抓取数据的实际案例.爬虫代码一般具有时效性,当 ...

  2. 【JAVA系列】Google爬虫如何抓取JavaScript的?

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[JAVA系列]Google爬虫如何抓取Java ...

  3. 让你从零开始学会写爬虫的5个教程(Python)

    写爬虫总是非常吸引IT学习者,毕竟光听起来就很酷炫极客,我也知道很多人学完基础知识之后,第一个项目开发就是自己写一个爬虫玩玩. 其实懂了之后,写个爬虫脚本是很简单的,但是对于新手来说却并不是那么容易. ...

  4. Node.js 教程 01 - 简介、安装及配置

    系列目录: Node.js 教程 01 - 简介.安装及配置 Node.js 教程 02 - 经典的Hello World Node.js 教程 03 - 创建HTTP服务器 Node.js 教程 0 ...

  5. Node.js 教程 04 - 模块系统

    前言: Node.js的模块系统类似于C/C++的文件引用,可以声明对象,也可以定义类 创建对象. 大家这么理解,就简单了. 定义: 为了让Node.js的文件可以相互调用,Node.js提供了一个简 ...

  6. Node.js教程系列~目录

    Node.js这个东西在近几年火起来了,而且会一直火下去,无论在infoq还是在cnblogs,csdn上,都可以到处看到它的样子,它主推的应该就是异步式I/O 吧,是的,设计的很完美,很吸引人,虽然 ...

  7. js基础到精通全面教程--JS教程

    适合阅读范围:对JavaScript一无所知-离精通只差一步之遥的人 基础知识:HTML JavaScript就这么回事1:基础知识 1 创建脚本块 1: <script language=”J ...

  8. MVVM开源框架Knot.js 教程2 - 大幅改变前端框架开发体验的Debugger

    Knotjs教程系列 1.CBS初步 2.Knot.js Debugger(本文) ....持续增加中 Knot.js 教程2 - 改变前端框架开发体验的Debugger Debugger只是一个方便 ...

  9. fedora环境安装webkit支持作爬虫下载解析JS

    环境: 我使用的fedora19.1-xfce版本,属于redhat系的桌面环境. 1.安装 webkit源码安装webkit失败,这里提供的是yum安装方式. a.查看当前yum库中的webkit资 ...

随机推荐

  1. MinDoc v0.6 发布,轻量级文档在线管理系统

    更新日志 新增 标签功能,可以根据标签组织项目 新增 用户删除功能,删除后的用户项目以及其他数据会自动转移到超级管理员账户上 新增 项目描述支持Markdown语法 优化 项目标签添加效果 优化 登录 ...

  2. Win8Metro(C#)数字图像处理--2.11图像锐化

    原文:Win8Metro(C#)数字图像处理--2.11图像锐化  [函数名称] 图像锐化函数SharpeningProcess(WriteableBitmap src,double sharpe ...

  3. Advanced Installer 中测试数据库连接提示“未发现数据源名称并且未指定默认驱动程序”的解决办法

    原文:Advanced Installer 中测试数据库连接提示"未发现数据源名称并且未指定默认驱动程序"的解决办法 最近需要制作一个安装包,安装包的要求如下: 1.用户手工填写M ...

  4. 如何在项目中添加Log4net_web.config

    <log4net> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleApp ...

  5. 利用Socket通信

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 建立网络通信连接至少要一对端口号(socket).socket本质是编程接口(API),对TCP/IP的封装 ...

  6. Linux日志系统

    常见的日志 常见的日志一般存储在/var/log中.常见的日志查看使用:ls/ll,cat/more/less查看即可:wtmp,lastlog使用last和lastlog提取其信息即可 配置日志 较 ...

  7. delphi多版本安装方法

    delphi tokyo和其他版本并存的安装方法 1.安装delphi 10.2 tokyo 破解后写入D:\Program Files (x86)\Embarcadero\Studio\19.0\b ...

  8. layer 1.9.2 发布,国产 Web 弹层不懈的前行者

    快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中.   <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...

  9. Qt:解析命令行(使用QCommandLineOption和QCommandLineParser)

    Qt从5.2版开始提供了两个类QCommandLineOption和QCommandLineParser来解析应用的命令行参数. 一.命令行写法命令行:"-abc" 在QComma ...

  10. Qt的QWaitCondition(允许线程在一定条件下唤醒其他线程,这样对不间断上传可能比较适用)

    对生产者和消费者问题的另一个解决办法是使用QWaitCondition,它允许线程在一定条件下唤醒其他线程.其中wakeOne()函数在条件满足时随机唤醒一个等待线程,而wakeAll()函数则在条件 ...