分类: 建站进阶

  • Windows 2016 服务器安全设置

    Windows 2016 服务器安全设置

    系统更新配置

    更换Windows更新服务器

    如果你觉得默认的Windows更新服务器比较慢,或者如果选择了阿里云或腾讯云服务器的话,可以更换Windows服务器。

    右键开始菜单图标,选择“运行”,然后输入gpedit.msc,依次选择 “计算机配置” – “管理模板” – “Windows 组件” – “Windows 更新”,双击“指定 Intranet Microsoft 更新服务位置”:

    202010041336571

    选中 已启用,然后设置检测更新的Intranet更新服务和统计服务器,如果是阿里云经典网络可以设置成 http://windowsupdate.aliyun-inc.com,阿里云VPC网络可以设置成 http://update.cloud.aliyuncs.com,腾讯云可以设置成 http://windowsupdate.tencentyun.com,备用下载服务器设置成 http://wsus.neu.edu.cn。

    202010041336572

    启用并允许自动更新

    双击“允许自动更新立即安装”,选择“已启用”启用自动更新。然后双击“配置自动更新”,选中“已启用”并配置成“自动下载并通知安装”,如下图:

    202010041336573

    设置完上述两步之后,需要以管理员角色执行下面的命令:

    gpupdate /force

    解决执行自动更新时出现的 0x8024401f 和 0x8024401c 错误
    完成上述操作之后,选择开始菜单-设置,执行检查更新,检查一下是否正常。
    如果出现 0x8024401f 或 0x8024401c 错误的话,以管理员身份执行下面的命令:

    net stop wuauserv
    reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate
    net start wuauserv

    系统账号安全

    设置账号安全策略

    在“运行”中执行secpol.msc命令,打开“本地安全策略”,进行如下设置:
    (1)“账户设置”-“密码策略”
    设置合适的密码复杂度,增强密码的强度。参考设置如下:

    202010041336574

    (2)“账户设置”-“账户锁定策略”
    设置账号密码出错之后的锁定时间,需要先设置“账户锁定阀值”才能设置其他两项,参考设置如下:

    202010041336575

    (3)“本地策略”-“安全选项”
    将“交互式登录: 不显示最后的用户名”设置为“启用”状态。

    检查并优化账号

    将账户安全设置完成之后,再对系统的账号进行优化。在“运行”中执行compmgmt.msc命令,打开“计算机管理”,然后在“系统工具”-“本地用户和组”-“用户”中查看是否有不用的账户,将不用的账户删除或停用。除此之外,还要在命令行中使用 net user 命令查看一遍有没有多余的账号(有的账号会在计算机管理中隐藏),可以使用 net user <username> /del 命令删除对应的账号。

    将默认的管理员用户名 Administrator 进行重命名,并且建议重新设置新的管理员密码。

    禁止系统自动登录

    系统休眠重新激活之后,需要密码才能登录系统。在“运行”中输入 control userpasswords2,打开“用户账户”,然后启用“要是用本机,用户必须输入用户名和密码”的选项。

    202010041336576

    远程访问安全

    更改远程终端默认3389端口

    将默认的远程终端端口3389修改成其他的端口。运行regedit打开注册表程序,需要修改注册表的两个地方:

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\Wds\repwd\Tds\tcp
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TerminalServer\WinStations\RDP-Tcp

    将上述两个地方右侧 PortNumber的值修改成新的端口号(建议将基数设置为十进制):

    202010041336587

    设置完成之后关闭注册表,然后重启服务器之后即可生效。如果设置防火墙的话,注意新端口加入防火墙的白名单中。

    将远程关机、本地关机和用户权限分配只授权给Administrtors组

    在“运行”中执行secpol.msc,打开“本地安全策略”窗口,依次打开“本地策略”-“用户权限分配”。
    (1)双击右侧的“从远程系统强制关机”,只保留“Administrators组”并将其他用户组删除;
    (2)双击右侧的“关闭系统”,只保留“Administrators组”并将其他用户组删除;
    (3)双击右侧的“取得文件或其它对象的所有权”,只保留“Administrators组”并将其他用户组删除;

    将远程登录账户设置为具体的管理员账号

    指定特定的管理员账号而不是Administrtors组,将增强登录系统的安全性,就算通过漏洞创建了Administrtors组的账号,也无法登录系统。

    在“运行”中执行secpol.msc,打开“本地安全策略”窗口,依次打开“本地策略”-“用户权限分配”。双击右侧的“从网络访问此计算机”,将所有的用户组删除,然后点击下面的“添加用户或组…”按钮,点击“高级”按钮,然后点击“立即查询”按钮,从查询的结果中选择管理员的账号,然后依次确定保存;

    系统网络安全

    关闭不需要的服务

    在“运行”中执行 services.msc 命令,打开“服务”,根据情况建议将以下服务改为禁用:

    Application Layer Gateway Service(为应用程序级协议插件提供支持并启用网络/协议连接)
    Background Intelligent Transfer Service(利用空闲的网络带宽在后台传输文件。如果服务被停用,例如Windows Update 和 MSN Explorer的功能将无法自动下载程序和其他信息)
    Computer Browser(维护网络上计算机的更新列表,并将列表提供给计算机指定浏览)
    DHCP Client
    Diagnostic Policy Service
    Distributed Link Tracking Client
    Distributed Transaction Coordinator
    DNS Client
    Print Spooler(管理所有本地和网络打印队列及控制所有打印工作)
    Remote Registry(使远程用户能修改此计算机上的注册表设置)
    Server(不使用文件共享可以关闭,关闭后再右键点某个磁盘选属性,“共享”这个页面就不存在了)
    Shell Hardware Detection
    TCP/IP NetBIOS Helper(提供 TCP/IP (NetBT) 服务上的NetBIOS 和网络上客户端的NetBIOS 名称解析的支持,从而使用户能够共享文件、打印和登录到网络)
    Task Scheduler(使用户能在此计算机上配置和计划自动任务)
    Windows Remote Management(47001端口,Windows远程管理服务,用于配合IIS管理硬件,一般用不到)
    Workstation(创建和维护到远程服务的客户端网络连接。如果服务停止,这些连接将不可用)

    关闭“同步主机_xxx”服务

    Windows 2016中有一个“同步主机_xxx”的服务,后面的xxx是一个数字,每个服务器不同。需要手动关闭,操作如下:
    首先在“运行”中执行regedit打开注册表,然后在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services 下面找到 OneSyncSvc、OneSyncSvc_xxx、UserDataSvc和UserDataSvc_xxx四个项,依次将其中的 start 值修改为4,退出注册表然后重启服务器即可。

    关闭IPC共享

    如果在上面停止并禁用 Server服务的话就不会出现IPC共享了,执行 net share 命令之后会提示“没有启动Server服务”,否则会类似C$、D$等默认共享,可以使用 net share C$ /del 命令进行删除。

    在注册表中找到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters,在右侧空白处右键,依次选择“新建”-“DWORD项”,名称设置为AutoShareServer,键值设置为0。

    202010041336588

    关闭139端口(Netbios服务)、445端口、5355端口(LLMNR)

    (1)关闭139端口
    依次打开“控制面板”-“查看网络状态和任务”,然后点击左侧的“更改适配器设置”,在网络连接中双击激活的网卡,点击“属性”按钮,双击“Internet 协议版本 4(TCP/IPv4)”,在打开的窗口中点击右下角的“高级”按钮,然后选择上面的“WINS”标签,在“NetBIOS设置”中选择“禁用 TCP/IP上的NetBIOS”,最后依次“确定”。

    202010041336589

    关闭此功能,你服务器上所有共享服务功能都将关闭,别人在资源管理器中将看不到你的共享资源。这样也防止了信息的泄露。

    (2)关闭445端口

    445端口是netbios用来在局域网内解析机器名的服务端口,一般服务器不需要对LAN开放什么共享,所以可以关闭。打开注册表,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBT\Parameters位置,在右侧右键并依次选择“新建”-“Dword值”,名称设置为SMBDeviceEnabled,值设置为0。

    (3)关闭5355端口(LLMNR)

    LLMNR本地链路多播名称解析,也叫多播DNS,用于解析本地网段上的名称,可以通过组策略关闭将其关闭。打开“运行”,输入gpedit.msc打开“本地组策略编辑器”,依次选择“计算机配置”-“管理模板”-“网络”-“DNS客户端”,在右侧双击“关闭多播名称解析”项,然后设置为“已禁用”。

    2020100413365810

    网络访问限制

    在“运行”中执行 secpol.msc 打开“本地安全策略”,打开“安全设置”-“本地策略”-“安全选项”,设置下面的策略:

    网络访问: 不允许 SAM 帐户的匿名枚举:已启用
    网络访问: 不允许 SAM 帐户和共享的匿名枚举:已启用
    网络访问: 将 Everyone 权限应用于匿名用户:已禁用
    帐户: 使用空白密码的本地帐户只允许进行控制台登录:已启用

    设置完成之后,在命令行(管理员身份)中执行 gpupdate /force 使其立即生效。

    日志审计

    增强日志记录

    增大日志量大小,避免由于日志文件容量过小导致日志记录不全。在“运行”中执行eventvwr.msc命令,打开“事件查看器”窗口,打开“Windows 日志”文件,分别右键下面的“应用程序”、“安全”和“系统”项,选择“属性”,修改“日志最大大小”为 20480。

    2020100413365811-1

    增强审核

    对系统事件进行记录,在日后出现故障时用于排查审计。在“运行”中执行secpol.msc命令,打开“本地安全策略”窗口,依次选择“安全设置”-“本地策略”-“审核策略”,建议将里面的项目设置如下:

    审核策略更改:成功
    审核登录事件:成功,失败
    审核对象访问:成功
    审核进程跟踪:成功,失败
    审核目录服务访问:成功,失败
    审核系统事件:成功,失败
    审核帐户登录事件:成功,失败
    审核帐户管理:成功,失败

    上面的项目设置成功之后,在“运行”中执行 gpupdate /force 命令使设置立即生效。

    开启并设置防火墙

    如果使用了云服务器(如阿里云、腾讯云等),云服务商会提供一个防火墙工具,通常是放在路由级别的,使用起来更方便,如果误操作的话也不会将自己排除在服务器上,因此建议优先采用云服务商提供的防火墙。

    开启或关闭Windows防火墙

    打开“控制面板”,依次选择“系统和安全”-“Windows防火墙”,选择左侧的“启用或关闭Windows防火墙”,根据需要选择启用或关闭Windows防火墙。如果采用了云服务商提供的防火墙的话,建议将Windows防火墙关闭。PS:开启防火墙之前需要允许远程登录的端口访问,否则远程连接会中断!

    允许特定的端口访问

    这里以Windows防火墙为例进行说明(其实云服务商提供的防火墙规则是类似的),前提是防火墙是启用的。在“运行”中执行 WF.msc 打开“高级安全 Windows 防火墙”,点击左侧的“入站规则”,然后点击右侧的“新建规则…”打开“新建入站规则向导”窗口,选择“端口”然后点击“下一步”按钮;端口类型选择“TCP”,下面选择“特定本地端口”,里面输入设置的远程登录端口以及Web端口,如:80, 433, 3389,然后点击“下一步”按钮;选择“允许连接”,然后点击“下一步”按钮;选中所有的选项,然后点击“下一步”;最后输入一个规则的名称,比如“允许远程连接和Web服务”,最后点击“完成”保存。

    关闭ICMP(禁ping)

    按照上面的步骤打开“高级安全 Windows 防火墙”并选中左侧的“入站规则”,从默认的规则里面双击“文件和打印机共享(回显请求 – ICMPv4-In)”,在“常规”中选中“已启用”,并在“操作”中选中“阻止连接”,最后“确定”保存即可。

    2020100413365812

    其它安全设置

    设置屏保,使本地攻击者无法直接恢复桌面控制

    打开“控制面板”,依次进入“外观和个性化”-“个性化”-“屏幕保护程序”,选择某一个屏保,然后选中“在恢复时显示登录屏幕”,并将等待时间设置为10分钟。

    2020100413365813

    关闭Windows自动播放功能

    在“运行”中执行gpedit.msc命令,依次打开“计算机配置”-“挂你模板”-“所有设置”,双击“关闭自动播放”,然后选择“已启用”。

    禁用IPV6。看操作。

    在windows server 2008/2016操作系统下部署weblogic web application,部署完成后进行测试,发现测试页的地址使用的是隧道适配器的地址,而不是静态的ip地址,而且所在的网络并没有ipv6接入,因此决定将ipv6和隧道适配器禁用,操作如下:
    禁用ipv6很简单,进入 控制面板\网络和 Internet\网络和共享中心 单击面板右侧“更改适配器设置”进入网络连接界面,选择要设置的连接,右键选择属性,取消Internet 协议版本 6 (TCP/IPv6) 前面的选择框确定即可。

    要禁用隧道适配器需要更改注册表信息,操作如下:
    开始 -> 运行 – > 输入 Regedit 进入注册表编辑器
    定位到:
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters]
    右键点击 Parameters,选择新建 -> DWORD (32-位)值
    命名值为 DisabledComponents,然后修改值为 ffffffff (16进制)
    重启后生效
    DisableComponents 值定义:
    0, 启用所有 IPv 6 组件,默认设置
    0xffffffff,禁用所有 IPv 6 组件, 除 IPv 6 环回接口
    0x20, 以前缀策略中使用 IPv 4 而不是 IPv 6
    0x10, 禁用本机 IPv 6 接口
    0x01, 禁用所有隧道 IPv 6 接口
    0x11, 禁用除用于 IPv 6 环回接口所有 IPv 6 接口

    OVER ! 重启下服务器吧

    技术员网小编补充

    其实很多情况下可以参考win2008 r2 服务器的安全设置。

    安装mcafee、安全狗、护卫神套件等。都有基本的安全设置,一键操作。但原理还是跟上面的一样,但自己手工操作的更利于个人技术的提升,第一次建议手工操作,然后再用工具检测一下。

  • Discuz防采集设置如何开启

    Discuz防采集设置如何开启

    如何保护好discuz论坛的内容不被别人采集,可以在论坛网站后台开启discuz防采集设置。

    方法/步骤

    1. 打开discuz网页后,直接点击打开登录页面,在登录页面输入管理员帐号和密码,然后点击登录,如下图所示。
      8601a18b87d6277f9cb80f3b24381f30e924fc0e
    2. 成功登录后,直接点击导航上面的【管理中心】,如下图所示。

      b7fd5266d0160924614d9f18d80735fae6cd344c
    3. 点击后跳转到discuz管理中心认证页面,直接输入密码,然后点击提交,如下图所示。
      d50735fae6cd7b894e040780032442a7d9330e4c
    4. 成功登录discuz管理中心后,直接点击导航栏里的【全局】,如下图所示。
      9213b07eca806538588d99109bdda144ad348249
    5. 在点击左侧全局列表里的【防采集设置】选项,如下图所示。
      0b55b319ebc4b745aafc8a15c3fc1e178a82154c
    6. 在打开的discuz防采集设置页面后,直接点击【是】开启防采集,如下图所示。
      8b13632762d0f7038818a8df04fa513d2697c50e
    7. 选择是后会显示出设置防采集的具体内容,然后根据提示填写,最后勾选哪些内容是要防止采集的,设置好后直接点击提交,如下图所示。
      7af40ad162d9f2d3457a19eca5ec8a136327cc4d
    8. 点击提交后,discuz提示当前设置更新成功。

    当然,这种防采集很容易被突破,参见这篇文章

    [b2_insert_post id=”217″]

  • 手把手教你购买充值,美区Apple ID礼品卡

    手把手教你购买充值,美区Apple ID礼品卡

    前段时间,我发了篇美区 Apple ID 注册教程的文章,没想到获得了几十万的阅读,想注册一个属于自己的Apple ID的同学可以看看。

    [b2_insert_post id=”22″]

    那么有了美区账号后该如何充值呢?

    这期就来填这个坑,手把手教大家购买/充值美区 Apple ID 礼品卡。

    我用该方法在去年12月份和今年1月份成功购买过两次美区的礼品卡。

    v2-29e54546a7b3b20d91a62bc7ab3f6f92_1440w.webp-2

    开始前给大家说几个注意事项,一定要认真看,毕竟充值美区礼品卡是要花钱的,我尽可能保证大家的成功率。

    一、充值前必看事项

    因为美区 Apple ID 是无法绑定国内信用卡的,所以要买付费 App 的话,只能通过购买礼品卡的方式给美区 Apple ID 账户充值,然后才能购买付费 App。

    注意点①:首先大家一定要清楚,通过这个方法充值的美区礼品卡只能购买付费 App,无法进行内购。什么是内购?比如游戏里面买各种道具,这种就属于内购。

    如果你充值是为了给游戏氪金,那千万别浪费这个钱了。

    注意点②:第二点是一定要准备一张国内的 VISA 或者万事达 mastercard 的信用卡,没有信用卡是无法购买的。

    注意点③:第三点是邮箱,我建议就用 Gmail 邮箱,如果用国内的邮箱有可能会收不到礼品卡的兑换码。

    具体怎么注册/登录 Gmail,我这边就不能多说了,大家自行去百度、知乎或者小红书上搜教程。

    邮箱注册完成后,一定要先给这个 Gmail 邮箱随便发个邮件测试一下,确保能收到邮件。

    二、美区礼品卡购买教程下面正式开始美区礼品卡的购买教程。

    首先打开 Safari 浏览器,在网址栏中输入 apple.com 进入美国苹果官网。

    进入网站后拉到底部点开 购物和学习 Shop and Learn 然后点击 礼品卡 Gift Card,接着点击中间的 购买按钮 Buy

    v2-cb1920d807ab89ab04e7bb54ae58be76_1440w.webp

    然后我们选 邮箱 Email,礼品卡的 LOGO 可以随便选,接着输入想要充值的金额,最低支持 10 美元

    v2-052198454576a59f6c502e8be982c3b6_1440w.webp

    接着需要填写一份送货信息。

    v2-78d078d7f8bfd2214256e1438295af7b_1440w.webp

    收卡人姓名可以随便填,收卡人 Email 地址这边填写上你的 Gmail 邮箱地址,这个是接收礼品卡卡号的邮箱,一定不要填错,确保邮箱能收到邮件。发送者姓名也可以随便填,发送者 Email 地址可以填你的 QQ 邮箱或者 163 邮箱都可以。接着个性化信息也可以随便填,比如“happy new year”。

    全部填写完后,点添加到 购物车 Add to Bag,然后点击 检查 Check Out

    v2-c6b93e5fea45170789078770c09f10bf_1440w.webp

    接着会提示你登录你的 Apple ID,这里我们直接登录中国区的 Apple ID 就行了,也就是你平时在用的那个。登录的好处就是,订单会与你的中国区 Apple ID 绑定,可随时查看发货进度。

    如何查看发货进度?

    依次打开Apple Store – 点击头像 – 订单即可查看。登录后可能会提示你,是否信任这个浏览器,点击 信任 Trust

    v2-ee7fc61a4ec69e66fdad73affadc98f7_1440w.webp

    到这里就可以开始填写付款信息了。我们选择第一个信用卡或借记卡 Credit or Debit Card。(因为购买美区礼品卡只能用美元,所以只能用国内的双币种信用卡)

    v2-b13647b4398cd56e0adfb1a14de84859_1440w.webp

    接着填写你的信用卡信息:

    从上到下依次是信用卡卡号、到期日期 VALID THRU 以及 CVV。

    v2-4d702c1b86fe14c2e4dc74ffdc3645c0_1440w.webp

    这个 CVV 就是卡片背面那个三位数,举个例子比如卡背面有 1234 567 七个数字,就是填后三位 567。接着填写账单地址 Billing Address:

    v2-add4ca68531f30147500314caba136d2_1440w.webp

    1.地区这边不用改,默认的美国 United States

    2.然后依次往下填写你信用卡中的名字,First Name填写你的名,Last Name这边填姓氏

    然后 街道、邮编、城市、手机号 这些信息可借助美国地址生成器生成。

    生成地址前,选填下面五个免税州:

    蒙大拿州 Montana

    俄勒冈州 Oregon

    阿拉斯加州 Alaska

    特拉华州 Delaware

    新罕布什尔州 New Hampshire

    三个美国地址生成器(点击这里获取)

    —————————

    我以第一个美国地址生成器网站为例。

    输入免税州的英文名称,例如 Montana,然后点击生成,网站会自动生成一份非常全的信息。

    v2-3602fca0b5d4a3a3f7137990d5326600_1440w.webp

    然后我们将信息填写到账单地址 Billing Address 中。

    v2-5003cb971308ea01450457fb2c56f7a3_1440w.webp

    第一个 街道 Street address 我们就复制美国地址生成器中生成的街道,邮编 Zip Code 也是直接从美国地址生成器中复制,填完邮编后下面的 城市 City,State 会自动帮你填写。

    接着 联系信息 Contact Information 这边需要填写我们前面填过的那个 Gmail 收件邮箱,手机号码就填美国地址生成器中生成的手机号,如果生成的手机号前面有+1,记得要去掉。

    全部填写完成后。

    我们拉到最后,点击 继续检查 Continue to Review

    v2-9ca8a01f12441d208b8a9ef4c7b819a5_1440w.webp

    接着检查一下之前填写的邮箱等信息。

    检查完成后,拉到底部,勾选条款,最后点 提交订单 Place Your Order

    v2-9da67bd1dafbd6ce8e06db05550ad19f_1440w.webp

    到这里我们就已经下单成功了,页面中会出现“你的订单已提交”的字样 Your order has been placed”。接着你的信用卡会收到交易提示,如果扣款成功,那就说明订单已经购买成功了。

    v2-9d39bb3f2557ef888d53152008127681_1440w.webp

    等待一段时间,之前填写的那个 Gmail 邮箱地址就会收到第一封邮件,提醒你“您的礼品卡订单正在处理中”。接着再等待 10-60 分钟,会收到第二封邮件,第二封邮件中包含了礼品卡的卡号,收到卡号后,我们就能给美区的 Apple ID 充值了。

    v2-5e8c928418a7b2d78ad24b1898ed49cf_1440w.webp

    第二封邮件可能有些小伙伴要等好几个小时候才会收到

    三、美区礼品卡充值教程

    打开收到的第二封邮件(内含美区礼品卡兑换码),拷贝礼品卡卡号。

    v2-703776b434c475bc49df7198165ce52d_1440w.webp

    然后打开 App Store,记得先登录你的美区账号。

    点击右上角的头像,然后点击 兑换礼品卡或代码 Redeem Gift Card or Code

    v2-ab92fe0b4f64cea338a5ef9b87855c40_1440w.webp

    把卡号粘贴到 输入代码 Enter Code Manually 处,最后点击右上角的 兑换 Redeem

    v2-47d6c467b7eacbb9638c42fe611bcd03_1440w.webp

    充值过程中可能会提示你输入美区 Apple ID 的密码,按提示输入即可。

    接着我们就可以看到,礼品卡已经充值成功,然后我们就可以去购买那些付费的 App 了。

    v2-7dabf3b5eaf1aefd25873af323d7adfb_1440w.webp

    四、其他购买美区礼品卡的方法

    如果没有条件申请到双币种信用卡,或者无法使用 Gmail 邮箱的同学,只能去淘宝、拼多多上买了。

    不过在上面买的话,有一定几率被封号,全看你运气,运气好了可能充十次都没问题,运气不好可能一次就被封了。所以这个大家自己选择,不过这也是门槛最低最方便的充值方法了。

  • 子比主题7.x版本破解方法

    子比主题7.x版本破解方法

    子比主题介绍:

    简约优雅的设计风格、模块化组件、商城支付系统,全面的前端功能、深度SEO优化、专注阅读体验。Zibll子主题是专为阅读网站而设计的,设计简单大方,功能全面。UI界面模块化,多种布局,多种显示效果可供选择,高度自由化,更容易匹配自己喜欢的网站。主题支持付费阅读、付费下载功能和用户VIP会员系统,为站长提供强大的生产力。

    子比主题7.x版本又更新了授权验证算法,这次只能通过改hosts来破解了。

    使用方法:
    搭建一个站点,绑定api.zibll.com域名,并开启SSL(随便找个域名的证书就行)

    上传本站下载的源码,并配置好伪静态

    最后在/etc/hosts里面加一行
    127.0.0.1 api.zibll.com

  • 7B2主题破解版4.3.8(4.4.1)安装的一些注意事项

    7B2主题破解版4.3.8(4.4.1)安装的一些注意事项

    B2 Pro是一款非常不错的wordpress主题,一直也被作者认为是不可能破解的。然而现在开心版还是来了。

    开心版链接如下,为防止泛滥,象征性收10积分,请大家谅解。

    [b2_insert_post id=”422″]

    以下是7B2主题破解版4.3.8(4.4.1)安装的一些注意事项:

    [content_hide]

    首先主题是完整可用的,请不要对程序怀疑而放弃。

    安装的环境一定要注意,因为可以后台报错了但是前台没有显示。建议打开后台的php的错误日志,这样能及时找到问题。

    环境就是正常的安装就可以,新手使用bt或者amh都是不错的选择。

    有几个常遇见的问题分享下:

    1,无法登陆,文章页面的右侧小工具都没有加载。这是因为缺少了php的扩展所至。安装一下bcmath这个扩展就可以了。

    2,jwt_auth一定不要装,因为本身模板已经包含了,如果再装一个jwt_auth,会出现冲突导致无法登陆。

    3,环境最高只支持到php7.4,请不要使用更高的版本。

    4,loader.so和ioncube是有冲突的,所以二者只能选一。

    [/content_hide]

    如果以上都注意一下,应该就可以正常运行了。

    本站就是基于破解版运行的。有bug大家可以评论区告诉我。

  • 如何将OTF / TTF文件转换为EOT格式?

    如何将OTF / TTF文件转换为EOT格式?

    最简单的方法就是使用

    font-face generator (everythingfonts.com)

    不仅会生成所有的web字体,还会把css自动生成好,无比的方便。

    @font-face {
      [font-family: <family-name>;]?
      [src: [ <uri> [format(<string>#)]? | <font-face-name> ]#;]?
      [unicode-range: <urange>#;]?
      [font-variant: <font-variant>;]?
      [font-feature-settings: normal|<feature-tag-value>#;]?
      [font-stretch: <font-stretch>;]?
      [font-weight: <weight>];
      [font-style: <style>];
    }

    使用字体松鼠发生器 – 这不仅会产生EOT,而且还会产生SVG和WOFF格式,并且一次转换多个字体文件,并将所有内容与相关的CSS一起提供到单个存档中。

    这里有一个快速的方法来从otf一步build立TTF和EOT版本。 当然,如果你不需要所有的东西,你可以把相关部分拉出来。 请注意,你从otf得到eot你必须去otf-> ttf-> eot。

    安装fontforge和ttf2eot。 他们在MacPorts中可用,不确定其他平台。

    将其保存为名为otf2ttf2eot.sh的脚本文件:

    (此脚本已更新为新的fontforge版本;原始脚本在post的末尾):

    #!/bin/sh otfFont="$1.otf" ttfFont="$1.ttf" eotFont="$1.eot" fontforge -c ' import fontforge font = fontforge.open("'$otfFont'") font.generate("'$ttfFont'") ' ttf2eot "$ttfFont" >"$eotFont"

    假设您有一个名为FontName.otf的字体,请运行:

    sh otf2ttf2eot.sh FontName

    旧版本fontforge的原始脚本:

    #!/bin/sh # Convert an OTF font into TTF an EOT formats. otfFont="$1.otf" ttfFont="$1.ttf" eotFont="$1.eot" fontforge -c ' Open("'$otfFont'"); Generate("'$ttfFont'"); Quit(0);' ttf2eot $ttfFont > $eotFont
  • JSJiaMi V6 解密工具

    JSJiaMi V6 解密工具

    解密效果

    源代码
    function cancelMacWithUserNameAndMac(userId, userMac, trid) {
    	var test = confirm("关闭无感认证后,只能在设备本机上再次开启!");
    	if (test) {
    		AuthInterFace.cancelMacWithUserNameAndMac(userId, userMac, function (data) {
    			if (data.result == 'success') {
    				//$("#"+trid).hide();
    				//$("#autoMacNumTip").html($("#autoMacNumTip").html()-1);
    				var userIndex = getQueryStringByName("userIndex");
    				AuthInterFace.freshOnlineUserInfo(userIndex, function (freshOnline) {
    					getTime = 1;
    					fillData();
    				});
    			} else {
    				alert(data.message);
    			}
    		});
    	}
    }
    加密后

    已省略全局解密函数

    为方便对比已进行格式化处理

    function cancelMacWithUserNameAndMac(_0x1437f8, _0x17c421, _0x18daca) {
    	var _0x18d784 = {
    		'OGRic': '4|2|6|8|0|5|7|3|9|1',
    		'AAvHe': function (_0x4a9629, _0x140a6c) {
    			return _0x4a9629(_0x140a6c);
    		},
    		'wIUwe': 'margin-left',
    		'TQJfu': '#loginFrameLogofood_hk_2',
    		'Ussjm': function (_0x3a631e, _0x5a538a) {
    			return _0x3a631e - _0x5a538a;
    		},
    		'mwhyn': function (_0x5c1515, _0x3e12d0) {
    			return _0x5c1515 * _0x3e12d0;
    		},
    		'eMmnc': '#hk_margin_left_1',
    		'pROLs': _0x64f0('9c5', 'DWlJ'),
    		'RtPyd': function (_0x1a2925, _0x3178e2) {
    			return _0x1a2925(_0x3178e2);
    		},
    		'ktmyn': _0x64f0('9c6', 'NMy2'),
    		'gxaAs': 'width',
    		'QzLeH': function (_0x52c760, _0x2740a1) {
    			return _0x52c760(_0x2740a1);
    		},
    		'MhTAi': _0x64f0('9c7', '*6xD'),
    		'FkPFD': '#leftId',
    		'izkEP': _0x64f0('9c8', 'a5h*'),
    		'qjdIA': function (_0x2af297, _0xb650bb) {
    			return _0x2af297 * _0xb650bb;
    		},
    		'feKqI': function (_0x1f7f78, _0x596751) {
    			return _0x1f7f78 === _0x596751;
    		},
    		'hmFcx': 'yhlbV',
    		'lNkRh': function (_0x16de55) {
    			return _0x16de55();
    		},
    		'mGvzI': _0x64f0('9c9', 'hSvn'),
    		'mjXUQ': function (_0x112f06, _0x404547) {
    			return _0x112f06 - _0x404547;
    		},
    		'dKWSL': function (_0x5dba1c, _0x2b83a9) {
    			return _0x5dba1c(_0x2b83a9);
    		},
    		'oOHzr': function (_0x3e2c53, _0x4c0c40) {
    			return _0x3e2c53 - _0x4c0c40;
    		},
    		'KnyVW': function (_0x1a0714, _0x336008) {
    			return _0x1a0714(_0x336008);
    		},
    		'oJrGK': function (_0x3f8456, _0x1ddba4) {
    			return _0x3f8456 / _0x1ddba4;
    		},
    		'hQFPI': function (_0xd930d9, _0x1db4bd) {
    			return _0xd930d9 - _0x1db4bd;
    		},
    		'EZHrV': function (_0x5ab773, _0x3893c7) {
    			return _0x5ab773(_0x3893c7);
    		},
    		'lMeUM': function (_0x34d463, _0x4d6b7b) {
    			return _0x34d463 - _0x4d6b7b;
    		},
    		'aycWe': function (_0x58ef0e, _0x3891ab) {
    			return _0x58ef0e - _0x3891ab;
    		},
    		'lKwci': _0x64f0('9ca', 'OJFQ'),
    		'ZkOVs': function (_0x4a6dbd, _0x4542cb) {
    			return _0x4a6dbd - _0x4542cb;
    		},
    		'zyJTu': function (_0x5e1b93, _0x446452) {
    			return _0x5e1b93 / _0x446452;
    		},
    		'vjWbs': function (_0x2575e0, _0x11c14c) {
    			return _0x2575e0 / _0x11c14c;
    		},
    		'NFCIT': _0x64f0('9cb', 'Zg5['),
    		'dsuhf': function (_0x89f937, _0x597b3f) {
    			return _0x89f937 + _0x597b3f;
    		},
    		'ncXTx': function (_0x12a7de, _0x22e70b) {
    			return _0x12a7de > _0x22e70b;
    		},
    		'lPPfO': function (_0x275710, _0x5a84db) {
    			return _0x275710(_0x5a84db);
    		},
    		'JBQXr': function (_0x287953, _0x123071, _0x2eab92) {
    			return _0x287953(_0x123071, _0x2eab92);
    		},
    		'AMUoZ': _0x64f0('9cc', 'NMy2'),
    		'OzLtF': _0x64f0('9cd', 'DWlJ'),
    		'TBrqo': 'userIndex',
    		'zaUUW': function (_0x43ad2d, _0x154b85) {
    			return _0x43ad2d !== _0x154b85;
    		},
    		'GJkAC': _0x64f0('9ce', 'gS57'),
    		'uJjdS': _0x64f0('9cf', 'y@FJ'),
    		'GKNWk': function (_0x446ff5, _0x613452) {
    			return _0x446ff5 !== _0x613452;
    		},
    		'PcETE': _0x64f0('9d0', 'tkAR')
    	};
    	var _0x3c08d6 = _0x18d784[_0x64f0('9d1', 'HmCh')](confirm, _0x18d784[_0x64f0('9d2', ')rYM')]);
    	if (_0x3c08d6) {
    		if (_0x18d784[_0x64f0('9d3', 'y@FJ')](_0x64f0('9d4', '7#T0'), _0x18d784['PcETE'])) {
    			var _0x2cfb1e = _0x18d784[_0x64f0('9d5', 'a5h*')][_0x64f0('9d6', 'z1V4')]('|'), _0x234a2d = 0x0;
    			while (!![]) {
    				switch (_0x2cfb1e[_0x234a2d++]) {
    					case'0':
    						_0x18d784[_0x64f0('9d7', 'fv0b')]($, _0x64f0('9d8', 'A4bS'))[_0x64f0('9d9', '*E$X')](_0x18d784['wIUwe'], $marginLeft - 0x64);
    						continue;
    					case'1':
    						$(_0x18d784[_0x64f0('9da', '7zoT')])[_0x64f0('871', 'G%jM')]('margin-left', _0x18d784['Ussjm'](0xc8, _0x18d784['mwhyn']($body, 0.1)));
    						continue;
    					case'2':
    						_0x18d784[_0x64f0('9db', 'TR]&')]($, _0x18d784['eMmnc'])['css'](_0x18d784['pROLs'], $marginLeft);
    						continue;
    					case'3':
    						_0x18d784[_0x64f0('9dc', 'JsoZ')]($, _0x18d784['ktmyn'])['css'](_0x18d784[_0x64f0('9dd', 'nO3k')], $width);
    						continue;
    					case'4':
    						if ($marginLeft < 0x6e) {
    							$marginLeft = 0x6e;
    						}
    						continue;
    					case'5':
    						_0x18d784[_0x64f0('9de', 'Zg5[')]($, _0x18d784['ktmyn'])['css'](_0x64f0('9df', 'xViR'), $marginLeft);
    						continue;
    					case'6':
    						_0x18d784[_0x64f0('9e0', 'xViR')]($, _0x18d784[_0x64f0('9e1', '8Vu)')])['css'](_0x18d784[_0x64f0('9e2', '(DaA')], $marginLeft);
    						continue;
    					case'7':
    						$(_0x18d784[_0x64f0('9e3', 't7O$')])['css'](_0x64f0('9e4', 'HmCh'), $width);
    						continue;
    					case'8':
    						$(_0x18d784[_0x64f0('9e5', '8Vu)')])[_0x64f0('289', 'hSvn')](_0x64f0('9e6', 'OJFQ'), $marginLeft - 0x6e);
    						continue;
    					case'9':
    						$(_0x18d784['izkEP'])[_0x64f0('26f', 'fv0b')](_0x18d784['wIUwe'], 0xc8 - _0x18d784[_0x64f0('9e7', 'kUYz')]($body, 0.1));
    						continue;
    				}
    				break;
    			}
    		} else {
    			AuthInterFace[_0x64f0('9e8', 'j510')](_0x1437f8, _0x17c421, function (_0x2380dc) {
    				var _0x3d57b1 = {
    					'MfrKs': function (_0x423e2b, _0x595c7e) {
    						return _0x18d784[_0x64f0('9e9', 'hY8M')](_0x423e2b, _0x595c7e);
    					},
    					'riefY': _0x18d784[_0x64f0('9ea', '8Vu)')],
    					'XnjaP': function (_0x154812, _0x17b089) {
    						return _0x18d784[_0x64f0('9eb', '4Ats')](_0x154812, _0x17b089);
    					},
    					'BtknR': function (_0x4afb84, _0x199c9f) {
    						return _0x18d784[_0x64f0('9ec', 'DWlJ')](_0x4afb84, _0x199c9f);
    					},
    					'qyGnJ': function (_0x489a77, _0x12aaa3) {
    						return _0x18d784[_0x64f0('9ed', 'Bk0K')](_0x489a77, _0x12aaa3);
    					},
    					'AFDMo': function (_0x4abfba, _0x219d81) {
    						return _0x18d784[_0x64f0('9eb', '4Ats')](_0x4abfba, _0x219d81);
    					},
    					'mPxnb': function (_0x3693d8, _0x598331) {
    						return _0x18d784['lPPfO'](_0x3693d8, _0x598331);
    					},
    					'eoqvl': function (_0x24b619, _0xfe706) {
    						return _0x18d784[_0x64f0('9ee', 'NMy2')](_0x24b619, _0xfe706);
    					},
    					'YICcj': '</div><div\x20class=\x27secondLine\x27>小时</div>',
    					'sUjOF': function (_0x1661d8, _0x395e79, _0x34d552) {
    						return _0x18d784['JBQXr'](_0x1661d8, _0x395e79, _0x34d552);
    					}
    				};
    				if (_0x18d784[_0x64f0('9ef', 'JsoZ')](_0x18d784['AMUoZ'], _0x18d784['OzLtF'])) {
    					limit = limit[_0x64f0('9f0', 'FBUA')](0x0, limit[_0x64f0('9f1', 'EeGR')]('B'));
    					limit = _0x3d57b1[_0x64f0('9f2', 'kUYz')](limit, 0x400) + 'KB';
    				} else {
    					if (_0x2380dc['result'] == _0x64f0('9f3', 'hSvn')) {
    						var _0x36923d = getQueryStringByName(_0x18d784[_0x64f0('9f4', 'fv0b')]);
    						AuthInterFace[_0x64f0('9f5', '3Pmi')](_0x36923d, function (_0x5c66cc) {
    							if (_0x18d784[_0x64f0('9f6', '(DaA')](_0x18d784['hmFcx'], 'IAutA')) {
    								var _0x130c29 = _0x3d57b1['riefY']['split']('|'), _0x5d6347 = 0x0;
    								while (!![]) {
    									switch (_0x130c29[_0x5d6347++]) {
    										case'0':
    											var _0x2d9053 = _0x3d57b1[_0x64f0('9f7', '3Pmi')](theTime2, '');
    											continue;
    										case'1':
    											if (_0x3d57b1['BtknR'](_0x2d9053[_0x64f0('9f8', 'Q((!')]('.'), -0x1)) {
    												_0x2d9053 = _0x2d9053['substring'](0x0, _0x2d9053['indexOf']('.'));
    											}
    											continue;
    										case'2':
    											if (_0x3d57b1[_0x64f0('9f9', 'j510')](_0x542dd2, 0x0)) {
    												_0x2d9053 = _0x3d57b1[_0x64f0('9fa', '7zoT')](_0x3d57b1[_0x64f0('9fb', '8Vu)')](parseInt, _0x2d9053), _0x542dd2);
    											}
    											continue;
    										case'3':
    											result = _0x3d57b1['AFDMo'](_0x3d57b1[_0x64f0('9fc', '7#T0')]('<div\x20class=\x27firstLine\x27>', _0x2d9053), _0x3d57b1['YICcj']);
    											continue;
    										case'4':
    											var _0x542dd2 = _0x3d57b1[_0x64f0('9fd', 'kUYz')](fomatFloat, _0x3d57b1[_0x64f0('9fe', '(DaA')](_0x3d57b1[_0x64f0('9ff', 'Lclw')](parseInt, theTime1), 0x3c), 0x1);
    											continue;
    									}
    									break;
    								}
    							} else {
    								getTime = 0x1;
    								_0x18d784[_0x64f0('a00', 'xViR')](fillData);
    							}
    						});
    					} else {
    						if (_0x18d784[_0x64f0('a01', 'DWlJ')](_0x18d784[_0x64f0('a02', 'hSvn')], _0x18d784[_0x64f0('a03', '*6xD')])) {
    							var _0x529cc9 = _0x18d784[_0x64f0('a04', 'A4bS')][_0x64f0('a05', 'EeGR')]('|'),
    								_0x5cbedb = 0x0;
    							while (!![]) {
    								switch (_0x529cc9[_0x5cbedb++]) {
    									case'0':
    										_0x18d784[_0x64f0('a06', 'wpSi')]($, _0x64f0('a07', 'tUE5'))[_0x64f0('894', 'nO3k')](_0x18d784[_0x64f0('a08', 'Lclw')], _0x18d784[_0x64f0('a09', 'F[EM')](_0x18d784[_0x64f0('a0a', 'F[EM')]($body, 0x384) / 0x2, 0xfa));
    										continue;
    									case'1':
    										_0x18d784[_0x64f0('a0b', 'tkAR')]($, '#divPop')['css'](_0x18d784[_0x64f0('a0c', 'fv0b')], _0x18d784['oOHzr'](_0x18d784[_0x64f0('a0d', '3Pmi')]($body, 0x384) / 0x2, 0xfa));
    										continue;
    									case'2':
    										_0x18d784['KnyVW']($, _0x64f0('a0e', ')rYM'))['css'](_0x18d784[_0x64f0('a0f', 'G%jM')], _0x18d784[_0x64f0('a10', 'wpSi')](_0x18d784[_0x64f0('a11', 'hSvn')]($body, 0x384), 0x2) - 0xfa);
    										continue;
    									case'3':
    										_0x18d784['EZHrV']($, _0x64f0('a12', 'G%jM'))[_0x64f0('4ed', '4Ats')](_0x64f0('a13', 'xViR'), _0x18d784[_0x64f0('a14', 'FBUA')](_0x18d784[_0x64f0('a15', 'Zg5[')](_0x18d784['aycWe']($body, 0x384), 0x2), 0xfa));
    										continue;
    									case'4':
    										$(_0x18d784[_0x64f0('a16', '4Ats')])['css'](_0x18d784['wIUwe'], _0x18d784[_0x64f0('a17', 'hSvn')](_0x18d784[_0x64f0('a18', 'Lclw')](_0x18d784[_0x64f0('a19', 'm*Jj')]($body, 0x384), 0x2), 0xd2));
    										continue;
    								}
    								break;
    							}
    						} else {
    							alert(_0x2380dc[_0x64f0('868', 'xViR')]);
    						}
    					}
    				}
    			});
    		}
    	}
    }
    解密后

    为方便对比已进行格式化处理

    function cancelMacWithUserNameAndMac(_0x1437f8, _0x17c421, _0x18daca) {
    	var _0x3c08d6 = confirm('关闭无感认证后,只能在设备本机上再次开启!');
    	if (_0x3c08d6) {
    		AuthInterFace.cancelMacWithUserNameAndMac(_0x1437f8, _0x17c421, function (_0x2380dc) {
    			if (_0x2380dc.result == 'success') {
    				var _0x36923d = getQueryStringByName('userIndex');
    				AuthInterFace.freshOnlineUserInfo(_0x36923d, function (_0x5c66cc) {
    					getTime = 1;
    					fillData();
    				});
    			} else {
    				alert(_0x2380dc.message);
    			}
    		});
    	}
    }

    功能介绍

    • 解除全局加密
      • 还原类似 _0x51f5('7', 'Ik*@') 的加密内容。
    • 解除代码块加密
      • 还原代码块中被统一收集的字符串及运算符。
    • 清理死代码(花指令)
      1. 清理仅包含常量字符串判断的 if 语句。
      2. 还原使用 switch...while 打乱顺序执行的语句。
    • 解除环境限制
      1. 解除 禁止控制台调试 限制。
      2. 解除 禁止控制台输出 限制。
      3. 解除 防止格式化 限制。
      4. 解除 安全域名 限制。
    • 提升代码可读性
      1. 合并串联字符串('spl'+'it' → 'split'
      2. 转换十六进制数字(0xf → 15
      3. 替换索引器(Object['keys'] → Object.keys
      4. 转换Unicode字符(\x22 → "
    • 格式化代码
      1. 将代码根据语句进行简易的代码缩进。
      2. 因能力有限且类似工具颇多,不做更多的优化和处理。

    使用须知

    • 解密文件中必须有且仅有通过某些特定的加密器加密的 JavaScript 代码(允许经过简单的格式化),解密前请将无关代码(如 HTML 的<script>标签或与加密脚本相关的非加密上下文)移除。
    • 某些特殊情况下,解密无法一次完成,可能需要使用不同的配置进行多次解密。
    • 注释和局部变量名在代码压缩、混淆的过程中已经丢失或被篡改,无法还原。
    • 在不安装依赖的情况下解密器将会使用 Node.js 内建的 vm 模块。若你无法安装依赖,请不要用于解密不可信的 JavaScript 文件。

    使用方法

    值得注意的是,请务必确保 config.json 文件存放在运行脚本时所在的文件夹(而不是解密器所在的文件夹,虽然它们通常是相同的)。

    1. 运行 npm install 。(可选,安装依赖后解密更安全)
    2. 根据需求在 config.json 中自定义配置。
    3. 运行 Jsjiemi.js 。

    输出结果

    每一解密步骤完成后,解密器都会输出一个结果文件

    你可以根据你的需求从以下结果中选择一个作为最终解密结果。

    支持通过配置文件修改输出文件的位置和命名格式。

    • JsjiemiResult0.js:净化代码
    • JsjiemiResult1.js:解除全局加密
    • JsjiemiResult2.js:解除代码块加密
    • JsjiemiResult3.js:清理死代码(花指令)
    • JsjiemiResult4.js:解除环境限制
    • JsjiemiResult5.js:提升代码可读性
    • JsjiemiResult6.js:格式化代码
  • 突破Discuz!的防采集

    突破Discuz!的防采集

    当短时间内频繁采集discuz,会触发discuz的防采集机制,默认打开的是一段javascript脚本,然后再通过跳转跳转到真实地址,这样子的情况下如何采集呢,本文将教会你如何破解这类型的防采集的采集。

    Discuz开启防采集后的采集方法,也就是帖子后面加了?dsign=这样子的

    Discuz在X3中增加了防采集功能,具体见Discuz x3.0防采集设置图文教程

    [b2_insert_post id=”558″]

    开启防采集后,访问DZ站点的伪静态链接如http://www.discuz.net/thread-3275423-1-1.html后面会跟上一个?_dsign=xxxxxx,正常链接如http://www.discuz.net/forum.php?mod=viewthread&tid=3305274会加上&_dsign=xxxxxx。这让人很不爽 (o#゜ 曲゜)o

    使用httplib2访问原帖子页面(下面以http://www.dz.net/forum.php?mod=viewthread&tid=768为例),返回的是一段混淆过的js,如:

    <script type="text/javascript">RKbW=function(){'RKbW';var _R=function(){return '=76'}; return _R();};function AIV(AIV_){function _A(AIV_){function ph(){return getName();}function AIV_(){}return ph();return AIV_}; return _A(AIV_);}DmZP='iew';_IX161 = 'assign';function zoQ(zoQ_){function ti(){return getName();};return ti();return 'zoQ'}function r2oe(){'return r2oe';return 'ad&'}_eloda = 'replace';F59s=function(){'return F59s';return 'p?m';};HP=function(){'return HP';return 'n';};function getName(){var caller=getName.caller;if(caller.name){return caller.name} var str=caller.toString().replace(/[\s]*/g,"");var name=str.match(/^function([^\(]+?)\(/);if(name && name[1]){return name[1];} else {return '';}}uM=function(){'return uM';return '9';};eG9=function(eG9_){'return eG9';return eG9_;};function kp(kp_){function _k(kp_){function o(){return getName();}function kp_(){}return o();return kp_}; return _k(kp_);}vD='1';BN=function(){'BN';var _B=function(){return 'r'}; return _B();};HALw='rum';_RZnE9 = 'href';o5y=function(o5y_){'return o5y';return o5y_;};function PH(){'return PH';return '.'}_BDkwZ = location;function w2(){'return w2';return '_'}KTI4=function(){'return KTI4';return '910';};_NUuAJ = window;wX=function(){'wX';var _w=function(){return 'd'}; return _w();};iyL=function(iyL_){'return iyL';return iyL_;};location.replace((function(){'return Q8mM';return '/fo'})()+HALw+PH()+AIV('Gs8')+F59s()+kp('nm')+(function(){'return njFH';return (function(){return 'd=v';})();})()+DmZP+eG9('th')+BN()+(function(){'return XD';return 'e'})()+r2oe()+zoQ('yKM')+wX()+RKbW()+'8&'+w2()+o5y('ds')+iyL('ig')+HP()+(function(){'return l26W';return '=6f'})()+uM()+(function(){'return by';return (function(){return '7';})();})()+KTI4()+vD);_NUuAJ['href']=(function(){'return Q8mM';return '/fo'})()+HALw+PH()+AIV('Gs8')+F59s()+kp('nm')+(function(){'return njFH';return (function(){return 'd=v';})();})()+DmZP;</script>

    显然这样人类是无法理解的……不过使用notepad++的JSFormat插件格式化后还是能看懂的嗯-v-

    实际上这是一个字符串替换然后重定向的脚本,生成原理如下(不完全按照上面的例子):

    • 原始字符串为location.href=forum.php?mod=viewthread&tid=768&_dsign=6f979101
    • 随机分割这个这个串,如分成l, oc, a, tio, n., ……
    • 对每一个子串替换成一个随机命名的函数,如l替换成_Oc9S(),则在脚本里加一句function _Oc9S(){return ‘l’;}以此类推
    • 每个function都可能加入奇怪的例如’return l;’这样毫无意义的混淆
    • 最后在末尾加上window.href=yyy,yyy为取forum.php?mod=viewthread&tid=768&_dsign=6f979101的前x个字符后得到一个子串

    我大概写得不清楚……就……这么个意思……

    [content_hide]

    毫无疑问要使用PyV8了,本来想自己写个解释器,但是算法太渣只能呜呼哀哉QAQ
    这里有个问题,PyV8只是一个js解释器的包装,不是浏览器的js运行时,因此location啊window啊都是undefined的,所以要手动把这些都去掉。(有一点要说明,就是由于js很骚,location.href有时会被写成location[‘href’],或者用location.assign或者location.replace,而assign和replace都可能被一个随机命名的变量替换掉了)

    dz-anti-anti-crawler

    直接看代码吧

    import PyV8
    import re
    js='''<script type="text/javascript">.........</script>'''
    #去掉<script>标签
    js=js[31:-9]
    for st in ['window','location',"'assign'","'href'","'replace'"]:
    equal=re.findall('[_A-Za-z0-9 =]+%s;'%st,js)#找到变量赋值等式
    if equal==[]:#有可能没有
    continue
    else:
    equal=equal[0]
    var=equal.split('=')[0].strip()#找出变量名
    #把等式干掉
    js=js.replace(equal,'')
    #把变量替换成它真正的意思
    js=js.replace(var,st)
    #把['xx'] 替换成 .xx
    js=js.replace("['%s']"%st.strip("'"),'.%s'%st.strip("'"))
    #将 window.href= 后的内容踢掉,因为当PyV8只输出最后一个等式的值
    if re.findall('window\.href=.+',js)!=[]:
    js=js.replace(re.findall('window\.href=.+',js)[0],'')
    #删掉location.xxx=
    js=js.replace('location.href=','').replace('location.replace','').replace('location.assign','')
    #交给你了-v-
    ctxt2 = PyV8.JSContext()
    ctxt2.enter()
    print ctxt2.eval(js)

    这样就得到了包含dsign的新url,可以继续爬了

    最后对DZ的防采集再说几句

    1. 防采集是对IP不对用户的
    2. 而且要看站长的设置,有可能只对帖子或日志等开启;你们可以到Discuz x3.0防采集设置图文教程感受一下
    3. _dsign的值是固定的,计算完一次js后可以考虑保存起来,以后可以直接访问加上_dsign的url
    4. 防采集是针对不支持js的机器人的,如果用python直接控制浏览器的话,可以无视之
    5. 如果mechanize和PyV8能合体那该多好~ o(* ̄▽ ̄*)o

    [/content_hide]

  • 爬虫神器Selenium全攻略

    爬虫神器Selenium全攻略

    今天带大家一起学(复)习模拟浏览器运行的库Selenium,它是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla FirefoxSafariGoogle ChromeOperaEdge等。

    这里我将以Chrome为例进行Selenium功能的演示~

    0. 准备工作

    在开始后续功能演示之前,我们需要先安装Chrome浏览器并配置好ChromeDriver,当然也需要安装selenium库!

    0.1. 安装selenium库

    pip install selenium

    0.2. 安装浏览器驱动

    其实,有两种方式安装浏览器驱动:一种是常见的手动安装,另一种则是利用第三方库自动安装。

    以下前提:大家都已经安装好了Chrome浏览器哈

    手动安装

    先查看本地Chrome浏览器版本:(两种方式均可)

    • 在浏览器的地址栏键入Chrome://version,即可查看浏览器版本号
    • 或者点击Chrome菜单 帮助关于Google Chrome,查看浏览器版本号

    再选择对应版本号的驱动版本

    下载地址:https://chromedriver.storage.googleapis.com/index.html

    最后进行环境变量配置,也就是将对应的ChromeDriver的可执行文件chromedriver.exe文件拖到PythonScripts目录下。

    注:当然也可以不这样做,但是在调用的时候指定chromedriver.exe绝对路径亦可。

    自动安装

    自动安装需要用到第三方库webdriver_manager,先安装这个库,然后调用对应的方法即可。

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from webdriver_manager.chrome import ChromeDriverManager
    
    browser = webdriver.Chrome(ChromeDriverManager().install())
    
    browser.get('http://www.baidu.com')
    search = browser.find_element_by_id('kw')
    search.send_keys('python')
    search.send_keys(Keys.ENTER)
    
    # 关闭浏览器
    browser.close()

    在上述代码中,ChromeDriverManager().install()方法就是自动安装驱动的操作,它会自动获取当前浏览器的版本并去下载对应的驱动到本地。

    ====== WebDriver manager ======
    Current google-chrome version is 96.0.4664
    Get LATEST chromedriver version for 96.0.4664 google-chrome
    There is no [win32] chromedriver for browser  in cache
    Trying to download new driver from https://chromedriver.storage.googleapis.com/96.0.4664.45/chromedriver_win32.zip
    Driver has been saved in cache [C:\Users\Gdc\.wdm\drivers\chromedriver\win32\96.0.4664.45]

    如果本地已经有该浏览器渠道,则会提示其已存在。

    ====== WebDriver manager ======
    Current google-chrome version is 96.0.4664
    Get LATEST driver version for 96.0.4664
    Driver [C:\Users\Gdc\.wdm\drivers\chromedriver\win32\96.0.4664.45\chromedriver.exe] found in cache

    搞定以上准备工作,我们就可以开始本文正式内容的学习啦~

    1. 基本用法

    这节我们就从初始化浏览器对象、访问页面、设置浏览器大小、刷新页面和前进后退等基础操作。

    1.1. 初始化浏览器对象

    在准备工作部分我们提到需要将浏览器渠道添加到环境变量或者指定绝对路径,前者可以直接初始化后者则需要进行指定。

    from selenium import webdriver
    
    # 初始化浏览器为chrome浏览器
    browser = webdriver.Chrome()
    
    # 指定绝对路径的方式
    path = r'C:\Users\Gdc\.wdm\drivers\chromedriver\win32\96.0.4664.45\chromedriver.exe'
    browser = webdriver.Chrome(path)
    
    # 关闭浏览器
    browser.close()

    可以看到以上是有界面的浏览器,我们还可以初始化浏览器为无界面的浏览器

    from selenium import webdriver
    
    # 无界面的浏览器
    option = webdriver.ChromeOptions()
    option.add_argument("headless")
    browser = webdriver.Chrome(options=option)
    
    # 访问百度首页
    browser.get(r'https://www.baidu.com/')
    # 截图预览
    browser.get_screenshot_as_file('截图.png')
    
    # 关闭浏览器
    browser.close()

    完成浏览器对象的初始化后并将其赋值给了browser对象,接下来我们就可以调用browser来执行各种方法模拟浏览器的操作了。

    1.2. 访问页面

    进行页面访问使用的是get方法,传入参数为待访问页面的URL地址即可。

    from selenium import webdriver
    
    # 初始化浏览器为chrome浏览器
    browser = webdriver.Chrome()
    
    # 访问百度首页
    browser.get(r'https://www.baidu.com/')
    
    # 关闭浏览器
    browser.close()

    1.3. 设置浏览器大小

    set_window_size()方法可以用来设置浏览器大小(就是分辨率),而maximize_window则是设置浏览器为全屏!

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    # 设置浏览器大小:全屏
    browser.maximize_window()   
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 设置分辨率 500*500
    browser.set_window_size(500,500)  
    time.sleep(2)
    
    # 设置分辨率 1000*800
    browser.set_window_size(1000,800) 
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    这里就不截图了,大家自行演示看效果哈~

    1.4. 刷新页面

    刷新页面是我们在浏览器操作时很常用的操作,这里refresh()方法可以用来进行浏览器页面刷新。

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    # 设置浏览器全屏
    browser.maximize_window()   
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    try:
        # 刷新页面
        browser.refresh()  
        print('刷新页面')
    except Exception as e:
        print('刷新失败')
       
    # 关闭浏览器
    browser.close()

    大家也是自行演示看效果哈,同F5快捷键。

    1.5. 前进后退

    前进后退也是我们在使用浏览器时非常常见的操作,这里forward()方法可以用来实现前进,back()可以用来实现后退。

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    # 设置浏览器全屏
    browser.maximize_window()   
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 打开淘宝页面
    browser.get(r'https://www.taobao.com')  
    time.sleep(2)
    
    # 后退到百度页面
    browser.back()  
    time.sleep(2)
    
    # 前进的淘宝页面
    browser.forward() 
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    2. 获取页面基础属性

    当我们用selenium打开某个页面,有一些基础属性如网页标题、网址、浏览器名称、页面源码等信息。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com') 
    
    # 网页标题
    print(browser.title)
    # 当前网址
    print(browser.current_url)
    # 浏览器名称
    print(browser.name)
    # 网页源码
    print(browser.page_source)

    输出如下:

    百度一下,你就知道
    https://www.baidu.com/
    chrome
    <html><head><script async="" src="https://passport.baidu.com/passApi/js/wrapper.js?cdnversion=1640515789507&amp;_=1640515789298"></script><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color"..."
    

    需要注意的是,这里的页面源码我们就可以用正则表达式Bs4xpath以及pyquery等工具进行解析提取想要的信息了。

    3. 定位页面元素

    我们在实际使用浏览器的时候,很重要的操作有输入文本、点击确定等等。对此,Selenium提供了一系列的方法来方便我们实现以上操作。常说的8种定位页面元素的操作方式,我们一一演示一下!

    我们以百度首页的搜索框节点为例,搜索python

    搜索框的html结构:

    <input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">

    3.1. id定位

    find_element_by_id()根据id属性获取,这里id属性是 kw

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_id('kw').send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    3.2. name定位

    find_element_by_name()根据name属性获取,这里name属性是 wd

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_name('wd').send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    3.3. class定位

    find_element_by_class_name()根据class属性获取,这里class属性是s_ipt

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_class_name('s_ipt').send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    3.4. tag定位

    我们知道HTML是通过tag来定义功能的,比如input是输入,table是表格等等。每个元素其实就是一个tag,一个tag往往用来定义一类功能,我们查看百度首页的html代码,可以看到有很多同类tag,所以其实很难通过tag去区分不同的元素。

    find_element_by_tag_name()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_tag_name('input').send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    由于存在多个input,以上代码会报错。

    3.5. link定位

    这种方法顾名思义就是用来定位文本链接的,比如百度首页上方的分类模块链接。

    find_element_by_link_text()

    以新闻为例

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 点击新闻 链接
    browser.find_element_by_link_text('新闻').click()
    time.sleep(2)
    
    # 关闭浏览器全部页面
    browser.quit()

    3.6. partial定位

    有时候一个超链接的文本很长,我们如果全部输入,既麻烦,又显得代码很不美观,这时候我们就可以只截取一部分字符串,用这种方法模糊匹配了。

    find_element_by_partial_link_text()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 点击新闻 链接
    browser.find_element_by_partial_link_text('闻').click()
    time.sleep(2)
    
    # 关闭浏览器全部页面
    browser.quit()

    3.7. xpath定位

    前面介绍的几种定位方法都是在理想状态下,有一定使用范围的,那就是:在当前页面中,每个元素都有一个唯一idnameclass超链接文本的属性,那么我们就可以通过这个唯一的属性值来定位他们。

    但是在实际工作中并非有这么美好,那么这个时候我们就只能通过xpath或者css来定位了。

    find_element_by_xpath()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_xpath("//*[@id='kw']").send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    3.8. css定位

    这种方法相对xpath要简洁些,定位速度也要快些。

    find_element_by_css_selector()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 在搜索框输入 python
    browser.find_element_by_css_selector('#kw').send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    3.9. find_element的By定位

    除了上述的8种定位方法,Selenium还提供了一个通用的方法find_element(),这个方法有两个参数:定位方式和定位值。

    # 使用前先导入By类
    from selenium.webdriver.common.by import By

    以上的操作可以等同于以下:

    browser.find_element(By.ID,'kw')
    browser.find_element(By.NAME,'wd')
    browser.find_element(By.CLASS_NAME,'s_ipt')
    browser.find_element(By.TAG_NAME,'input')
    browser.find_element(By.LINK_TEXT,'新闻')
    browser.find_element(By.PARTIAL_LINK_TEXT,'闻')
    browser.find_element(By.XPATH,'//*[@id="kw"]')
    browser.find_element(By.CSS_SELECTOR,'#kw')

    3.10. 多个元素

    如果定位的目标元素在网页中不止一个,那么则需要用到find_elements,得到的结果会是列表形式。简单来说,就是element后面多了复数标识s,其他操作一致。

    4. 获取页面元素属性

    既然我们有很多方式来定位页面的元素,那么接下来就可以考虑获取以下元素的属性了,尤其是用Selenium进行网络爬虫的时候。

    4.1. get_attribute获取属性

    以百度首页的logo为例,获取logo相关属性

    <img hidefocus="true" id="s_lg_img" class="index-logo-src" src="//www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" width="270" height="129" onerror="this.src='//www.baidu.com/img/flexible/logo/pc/index.png';this.onerror=null;" usemap="#mp">

    获取logo的图片地址

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    
    logo = browser.find_element_by_class_name('index-logo-src')
    print(logo)
    print(logo.get_attribute('src'))
    
    # 关闭浏览器
    browser.close()

    输出:

    <selenium.webdriver.remote.webelement.WebElement (session="e95b18c43a330745af019e0041f0a8a4", element="7dad5fc0-610b-45b6-b543-9e725ee6cc5d")>
    https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png

    4.2. 获取文本

    以热榜为例,获取热榜文本和链接

    <a class="title-content tag-width c-link c-font-medium c-line-clamp1" href="https://www.baidu.com/s?cl=3&amp;tn=baidutop10&amp;fr=top1000&amp;wd=%E5%90%84%E5%9C%B0%E8%B4%AF%E5%BD%BB%E5%8D%81%E4%B9%9D%E5%B1%8A%E5%85%AD%E4%B8%AD%E5%85%A8%E4%BC%9A%E7%B2%BE%E7%A5%9E%E7%BA%AA%E5%AE%9E&amp;rsv_idx=2&amp;rsv_dl=fyb_n_homepage&amp;sa=fyb_n_homepage&amp;hisfilter=1" target="_blank"><span class="title-content-index c-index-single c-index-single-hot1">1</span><span class="title-content-title">各地贯彻十九届六中全会精神纪实</span></a>

    获取热榜的文本,用的是text属性,直接调用即可

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    
    logo = browser.find_element_by_css_selector('#hotsearch-content-wrapper > li:nth-child(1) > a')
    print(logo.text)
    print(logo.get_attribute('href'))
    
    # 关闭浏览器
    browser.close()

    输出:

    1各地贯彻十九届六中全会精神纪实
    https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%90%84%E5%9C%B0%E8%B4%AF%E5%BD%BB%E5%8D%81%E4%B9%9D%E5%B1%8A%E5%85%AD%E4%B8%AD%E5%85%A8%E4%BC%9A%E7%B2%BE%E7%A5%9E%E7%BA%AA%E5%AE%9E&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1

    4.3. 获取其他属性

    除了属性和文本值外,还有id、位置、标签名和大小等属性。

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    
    browser.get(r'https://www.baidu.com')  
    
    logo = browser.find_element_by_class_name('index-logo-src')
    print(logo.id)
    print(logo.location)
    print(logo.tag_name)
    print(logo.size)
    
    # 关闭浏览器
    browser.close()

    输出:

    6af39c9b-70e8-4033-8a74-7201ae09d540
    {'x': 490, 'y': 46}
    img
    {'height': 129, 'width': 270}

    5. 页面交互操作

    页面交互就是在浏览器的各种操作,比如上面演示过的输入文本、点击链接等等,还有像清除文本、回车确认、单选框与多选框选中等。

    5.1. 输入文本

    其实,在之前的小节中我们有用过此操作。

    send_keys()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 定位搜索框
    input = browser.find_element_by_class_name('s_ipt')
    # 输入python
    input.send_keys('python')
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    5.2. 点击

    同样,我们也用过这个点击操作。

    click()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 选中新闻按钮
    click = browser.find_element_by_link_text('新闻')
    # 点击之
    click.click()
    time.sleep(2)
    
    # 关闭浏览器全部页面
    browser.quit()

    5.3. 清除文本

    既然有输入,这里也就有清除文本啦。

    clear()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 定位搜索框
    input = browser.find_element_by_class_name('s_ipt')
    # 输入python
    input.send_keys('python')
    time.sleep(2)
    # 清除python
    input.clear()
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    5.4. 回车确认

    比如,在搜索框输入文本python,然后回车就出查询操作结果的情况。

    submit()

    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 定位搜索框
    input = browser.find_element_by_class_name('s_ipt')
    # 输入python
    input.send_keys('python')
    time.sleep(2)
    # 回车查询
    input.submit()
    time.sleep(5)
    
    # 关闭浏览器
    browser.close()

    5.5. 单选

    单选比较好操作,先定位需要单选的某个元素,然后点击一下即可。

    5.6. 多选

    多选好像也比较容易,依次定位需要选择的元素,点击即可。

    5.7. 下拉框

    下拉框的操作相对复杂一些,需要用到Select模块。

    先导入该类

    from selenium.webdriver.support.select import Select

    select模块中有以下定位方法

    '''1、三种选择某一选项项的方法'''
    
    select_by_index()           # 通过索引定位;注意:index索引是从“0”开始。
    select_by_value()           # 通过value值定位,value标签的属性值。
    select_by_visible_text()    # 通过文本值定位,即显示在下拉框的值。
    
    '''2、三种返回options信息的方法'''
    
    options                     # 返回select元素所有的options
    all_selected_options        # 返回select元素中所有已选中的选项
    first_selected_options      # 返回select元素中选中的第一个选项                  
    
    
    '''3、四种取消选中项的方法'''
    
    deselect_all                # 取消全部的已选择项
    deselect_by_index           # 取消已选中的索引项
    deselect_by_value           # 取消已选中的value值
    deselect_by_visible_text    # 取消已选中的文本值

    我们来进行演示一波,由于暂时没找到合适的网页,我这边写了一个简单的网页本地测试(文件存为 帅哥.html)

    <html>
    
    <body>
    
    <form>
    <select name="帅哥">
    <option value="才哥">才哥</option>
    <option value="小明" selected="">小明</option>
    <option value="小华">小华</option>
    <option value="草儿">小草</option>
    </select>
    </form>
    
    </body>
    </html>

    然后,再演示下拉框的不同选择的方式

    from selenium import webdriver
    from selenium.webdriver.support.select import Select
    import time
    
    url = 'file:///C:/Users/Gdc/Desktop/帅哥.html'
    
    browser = webdriver.Chrome()
    
    browser.get(url)
    time.sleep(2)
    
    # 根据索引选择
    Select(browser.find_element_by_name("帅哥")).select_by_index("2")
    time.sleep(2)
    # 根据value值选择
    Select(browser.find_element_by_name("帅哥")).select_by_value("草儿")
    time.sleep(2)
    # 根据文本值选择
    Select(browser.find_element_by_name("帅哥")).select_by_visible_text("才哥")
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()
    动图封面

    6. 多窗口切换

    比如同一个页面的不同子页面的节点元素获取操作,不同选项卡之间的切换以及不同浏览器窗口之间的切换操作等等。

    6.1. Frame切换

    Selenium打开一个页面之后,默认是在父页面进行操作,此时如果这个页面还有子页面,想要获取子页面的节点元素信息则需要切换到子页面进行擦走,这时候switch_to.frame()就来了。如果想回到父页面,用switch_to.parent_frame()即可。

    6.2. 选项卡切换

    我们在访问网页的时候会打开很多个页面,在Selenium中提供了一些方法方便我们对这些页面进行操作。

    current_window_handle:获取当前窗口的句柄。
    window_handles:返回当前浏览器的所有窗口的句柄。
    switch_to_window():用于切换到对应的窗口。

    from selenium import webdriver
    import time
    
    browser = webdriver.Chrome()
    
    # 打开百度
    browser.get('http://www.baidu.com')
    # 新建一个选项卡
    browser.execute_script('window.open()')
    print(browser.window_handles)
    # 跳转到第二个选项卡并打开知乎
    browser.switch_to.window(browser.window_handles[1])
    browser.get('http://www.zhihu.com')
    # 回到第一个选项卡并打开淘宝(原来的百度页面改为了淘宝)
    time.sleep(2)
    browser.switch_to.window(browser.window_handles[0])
    browser.get('http://www.taobao.com')

    7. 模拟鼠标操作

    既然是模拟浏览器操作,自然也就需要能模拟鼠标的一些操作了,这里需要导入ActionChains 类。

    from selenium.webdriver.common.action_chains import ActionChains

    7.1. 左键

    这个其实就是页面交互操作中的点击click()操作。

    7.2. 右键

    context_click()

    from selenium.webdriver.common.action_chains import ActionChains
    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 定位到要右击的元素,这里选的新闻链接
    right_click = browser.find_element_by_link_text('新闻')
    
    # 执行鼠标右键操作
    ActionChains(browser).context_click(right_click).perform()
    time.sleep(2)
    
    # 关闭浏览器
    browser.close()

    在上述操作中

    ActionChains(browser):调用ActionChains()类,并将浏览器驱动browser作为参数传入
    context_click(right_click):模拟鼠标双击,需要传入指定元素定位作为参数
    perform():执行ActionChains()中储存的所有操作,可以看做是执行之前一系列的操作

    7.3. 双击

    double_click()

    from selenium.webdriver.common.action_chains import ActionChains
    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')  
    time.sleep(2)
    
    # 定位到要双击的元素
    double_click = browser.find_element_by_css_selector('#bottom_layer > div > p:nth-child(8) > span')
    
    # 双击
    ActionChains(browser).double_click(double_click).perform()
    time.sleep(15)
    
    # 关闭浏览器
    browser.close()

    7.4. 拖拽

    drag_and_drop(source,target)拖拽操作嘛,开始位置和结束位置需要被指定,这个常用于滑块类验证码的操作之类。

    我们以菜鸟教程的一个案例来进行演示

    https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    browser.get(url)  
    time.sleep(2)
    
    browser.switch_to.frame('iframeResult')
    
    # 开始位置
    source = browser.find_element_by_css_selector("#draggable")
    
    # 结束位置
    target = browser.find_element_by_css_selector("#droppable")
    
    # 执行元素的拖放操作
    actions = ActionChains(browser)
    actions.drag_and_drop(source, target)
    actions.perform()
    # 拖拽
    time.sleep(15)
    
    # 关闭浏览器
    browser.close()
    动图封面

    7.5. 悬停

    move_to_element()

    from selenium.webdriver.common.action_chains import ActionChains
    from selenium import webdriver
    import time  
    
    browser = webdriver.Chrome()
    url = 'https://www.baidu.com'
    browser.get(url)  
    time.sleep(2)
    
    # 定位悬停的位置
    move = browser.find_element_by_css_selector("#form > span.bg.s_ipt_wr.new-pmd.quickdelete-wrap > span.soutu-btn")
    
    # 悬停操作
    ActionChains(browser).move_to_element(move).perform()
    time.sleep(5)
    
    # 关闭浏览器
    browser.close()

    8. 模拟键盘操作

    selenium中的Keys()类提供了大部分的键盘操作方法,通过send_keys()方法来模拟键盘上的按键。

    引入Keys

    from selenium.webdriver.common.keys import Keys

    常见的键盘操作

    send_keys(Keys.BACK_SPACE):删除键(BackSpace)
    send_keys(Keys.SPACE):空格键(Space)
    send_keys(Keys.TAB):制表键(TAB)
    send_keys(Keys.ESCAPE):回退键(ESCAPE)
    send_keys(Keys.ENTER):回车键(ENTER)
    send_keys(Keys.CONTRL,'a'):全选(Ctrl+A)
    send_keys(Keys.CONTRL,'c'):复制(Ctrl+C)
    send_keys(Keys.CONTRL,'x'):剪切(Ctrl+X)
    send_keys(Keys.CONTRL,'v'):粘贴(Ctrl+V)
    send_keys(Keys.F1):键盘F1
    …..
    send_keys(Keys.F12):键盘F12

    实例操作演示:

    定位需要操作的元素,然后操作即可!

    from selenium.webdriver.common.keys import Keys
    from selenium import webdriver
    import time
    
    browser = webdriver.Chrome()
    url = 'https://www.baidu.com'
    browser.get(url)  
    time.sleep(2)
    
    # 定位搜索框
    input = browser.find_element_by_class_name('s_ipt')
    # 输入python
    input.send_keys('python')
    time.sleep(2)
    
    # 回车
    input.send_keys(Keys.ENTER)
    time.sleep(5)
    
    # 关闭浏览器
    browser.close()

    9. 延时等待

    如果遇到使用ajax加载的网页,页面元素可能不是同时加载出来的,这个时候尝试在get方法执行完成时获取网页源代码可能并非浏览器完全加载完成的页面。所以,这种情况下需要设置延时等待一定时间,确保全部节点都加载出来。

    三种方式可以来玩玩:强制等待、隐式等待和显式等待

    9.1. 强制等待

    就很简单了,直接time.sleep(n)强制等待n秒,在执行get方法之后执行。

    9.2. 隐式等待

    implicitly_wait()设置等待时间,如果到时间有元素节点没有加载出来,就会抛出异常。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    
    # 隐式等待,等待时间10秒
    browser.implicitly_wait(10)  
    
    browser.get('https://www.baidu.com')
    print(browser.current_url)
    print(browser.title)
    
    # 关闭浏览器
    browser.close()

    9.3. 显式等待

    设置一个等待时间和一个条件,在规定时间内,每隔一段时间查看下条件是否成立,如果成立那么程序就继续执行,否则就抛出一个超时异常。

    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    import time
    
    browser = webdriver.Chrome()
    browser.get('https://www.baidu.com')
    # 设置等待时间10s
    wait = WebDriverWait(browser, 10)
    # 设置判断条件:等待id='kw'的元素加载完成
    input = wait.until(EC.presence_of_element_located((By.ID, 'kw')))
    # 在关键词输入:关键词
    input.send_keys('Python')
    
    # 关闭浏览器
    time.sleep(2)
    browser.close()

    WebDriverWait的参数说明

    WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
    driver: 浏览器驱动
    timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
    poll_frequency: 每次检测的间隔时间,默认是0.5秒
    ignored_exceptions:超时后的异常信息,默认情况下抛出NoSuchElementException异常
    until(method,message=”)
    method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
    message: 如果超时,抛出TimeoutException,将message传入异常
    until_not(method,message=”)
    until_not 与until相反,until是当某元素出现或什么条件成立则继续执行,until_not是当某元素消失或什么条件不成立则继续执行,参数也相同。

    其他等待条件

    from selenium.webdriver.support import expected_conditions as EC
    
    # 判断标题是否和预期的一致
    title_is
    # 判断标题中是否包含预期的字符串
    title_contains
    
    # 判断指定元素是否加载出来
    presence_of_element_located
    # 判断所有元素是否加载完成
    presence_of_all_elements_located
    
    # 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0,传入参数是元组类型的locator
    visibility_of_element_located
    # 判断元素是否可见,传入参数是定位后的元素WebElement
    visibility_of
    # 判断某个元素是否不可见,或是否不存在于DOM树
    invisibility_of_element_located
    
    # 判断元素的 text 是否包含预期字符串
    text_to_be_present_in_element
    # 判断元素的 value 是否包含预期字符串
    text_to_be_present_in_element_value
    
    #判断frame是否可切入,可传入locator元组或者直接传入定位方式:id、name、index或WebElement
    frame_to_be_available_and_switch_to_it
    
    #判断是否有alert出现
    alert_is_present
    
    #判断元素是否可点击
    element_to_be_clickable
    
    # 判断元素是否被选中,一般用在下拉列表,传入WebElement对象
    element_to_be_selected
    # 判断元素是否被选中
    element_located_to_be_selected
    # 判断元素的选中状态是否和预期一致,传入参数:定位后的元素,相等返回True,否则返回False
    element_selection_state_to_be
    # 判断元素的选中状态是否和预期一致,传入参数:元素的定位,相等返回True,否则返回False
    element_located_selection_state_to_be
    
    #判断一个元素是否仍在DOM中,传入WebElement对象,可以判断页面是否刷新了
    staleness_of

    10. 其他

    补充一些

    10.1. 运行JavaScript

    还有一些操作,比如下拉进度条,模拟javaScript,使用execute_script方法来实现。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    # 知乎发现页
    browser.get('https://www.zhihu.com/explore')
    
    browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    browser.execute_script('alert("To Bottom")')

    10.2. Cookie

    selenium使用过程中,还可以很方便对Cookie进行获取、添加与删除等操作。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    # 知乎发现页
    browser.get('https://www.zhihu.com/explore')
    # 获取cookie
    print(f'Cookies的值:{browser.get_cookies()}')
    # 添加cookie
    browser.add_cookie({'name':'才哥', 'value':'帅哥'})
    print(f'添加后Cookies的值:{browser.get_cookies()}')
    # 删除cookie
    browser.delete_all_cookies()
    print(f'删除后Cookies的值:{browser.get_cookies()}')

    输出:

    Cookies的值:[{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1640537860'}, {'domain': '.zhihu.com', ...]
    添加后Cookies的值:[{'domain': 'www.zhihu.com', 'httpOnly': False, 'name': '才哥', 'path': '/', 'secure': True, 'value': '帅哥'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1640537860'}, {'domain': '.zhihu.com',...]
    删除后Cookies的值:[]

    以上就是本次有关Selenium的全部内容,后续我们将演示Selenium爬虫以及web自动化方面的一些实战案例,敬请期待!

  • 最新美区苹果账号5分钟简易注册法

    最新美区苹果账号5分钟简易注册法

    这篇文章教大家注册一个非常稳定的美区 Apple ID。

    我通过该方法注册过两个美区账号,还冲了钱,到目前已经使用两年了,没出现任何问题稳的很。

    话不多说,教程开始,只要跟着我的步骤走,百分百能成功。

    一、准备工作

    • 一个能接收短信的国内手机号
    • 一个全新邮箱(指从没注册过Apple ID的邮箱)
    • 美国地址生成器(后面我会给大家提供)4.无需任何代理工具

    注意以下四点可以避免很多问题:

    1. 出生日期:一定要设置成大于 18 周岁的日期,否则会导致部分应用由于年龄限制无法使用。
    2. 电子邮件:建议新注册一个全新的从未注册过 Apple ID 的邮箱,比如 163 邮箱。
    3. 手机号码:亲测,注册过中国区 Apple ID 的手机号码可以用来注册美区账号,不会产生冲突。
    4. 密码:设置密码时,密码中不要包含有名字、生日、邮箱中的信息,否则会卡在验证码那一步。

    二、注册教程

    为了方便大家注册,该方法全程都在手机中操作,不用借助电脑。

    首先进入美国 Apple ID 注册页面,复制下方网址至 Safari 浏览器中打开即可进入。

    具体注册方法如下长图,跟着我的步骤走就行了,一定要严格按照我写的要求操作。

    接着需要对电子邮件/手机号码进行验证。把收到的验证码输入进去,依次点击下一步就行了。

    注册成功后,账号会自动登录,如果没登录的话重新登录一遍刚注册的账号即可。

    接着点击退出登录左边的“箭头”然后点击付款方式,接着再点击添加付款方式。

    下一步是填写付款方式&账单地址,这步很关键,需要借助美国地址生成器,它会自动帮你生成街道地址、城市、邮编、电话号码等信息。

    生成地址前,建议选以下五个免税州:

    • 蒙大拿州(Montana)
    • 俄勒冈州(Oregon)
    • 阿拉斯加州(Alaska)
    • 特拉华州(Delaware)
    • 新罕布什尔州(New Hampshire)

    三个稳定美国地址生成器(点这里获取)

    下图中标注的由美国地址生成器生成的内容,直接复制美国地址生成器中生成的内容即可。

    接着勾选拷贝账单寄送地址,最后点击更新就行了。

    到这里我们的美区 Apple ID 就注册完成了!下面教大家如何登录。

    三、登录美区ID

    打开 App Store,首先退出当前账号。点击右上角的头像,然后拉到末尾,点击退出登录即可。

    接着再次点击 App Store 中右上角的头像,输入前面注册的美区账号&密码,点击登录即可。

    然后会跳出一个弹窗,选择检查即可,接着打开同意条款与条件,选择下一页。

    不要修改任何内容,直接点击下一页,然后点击继续。

    点击Continue,到这里我们的美区 Apple ID 就已经成功登录了。

    注册登录成功后,我们就能下载美区中的各种 App 了。

    四、一些需要注意的地方

    1.设置密码时,密码中不要包含前面填写的名字、生日、邮箱中的任何信息,否则可能会卡在验证码那一步,总之就是密码尽量原创一个。

    2.不要在「设置」中登录美区Apple ID,以免造成不必要的麻烦。下载美区 App 只需在 App Store 中登录即可,下载完后再换回国区账号即可,对 iCloud 等不会有任何影响。

    3.如果你有在用Apple Music,切换成美区后会导致已下载的歌曲全被清空。

    4.建议不要把美区 Apple ID 当成主力账号,需要下美区应用时登录就行了,以免出现啥问题。

    五、常见问题汇总

    ➊ 手机号码提示错误怎么解决?

    答:看看复制的号码是不是开头有数字”1″或者”+1″,有的话去掉即可。

    ➋ 更新 App 的时候显示账号被锁定,但可以下载未下载过的 App 是什么原因?

    答:因为你更新的这个 App 之前是用其他 Apple ID 下载的,所以这个 App 是和你之前下载时的那个 Apple ID 绑定在一起的,所以出现被锁定的提示是原先账号出了问题,和当前账号没关系。解决方法很简单,把 App 卸载重新安装即可。

    ➌ 邮编错误怎么办?

    答:估计是地址生成器网站数据库中的部分邮编有误,多生成几份地址试试即可。

    ➍ Your request could not be completed at this time 怎么办?

    答:应该是地址生成器生成的号码有问题,电话是 xxx-xxx-xxx 的正常,而 +1xxx-xxx-xxx 就不行。解决方法就是去掉号码开头的”1″或者”+1″即可。

    ➎ Cannot be created at this time 怎么办?

    答:切换成 4G、5G、或者换个浏览器、或者用电脑注册,或者次日再试试。

    ➏ 注册成功后,如何二次修改美区 Apple ID 的地址、姓名等信息?

    答:进入美国苹果官网,拉到底部找到 manage your apple id,登录后即可修改,不懂英文的同学可借助翻译。

    如果以上回答仍然无法解决你的问题,那建议用百度、必应、知乎等搜索工具去寻找解决方法。

    六、美区Apple ID礼品卡

    [b2_insert_post id=”525″]

    —————————

    创个美区 Apple ID 还是挺有必要的,可以下到许多国内没有上架的应用,和国区 Apple ID 两者互补,享受最全面的 App 下载体验。

    遇到各种问题,大家可以看评论区解决。