info AppiumDoctor Appium Doctor v.1.4.3 info AppiumDoctor ### Diagnostic starting ### info AppiumDoctor ✔ The Node.js binary was found at: /Users/chenwenguan/.nvm/versions/node/v8.9.3/bin/node info AppiumDoctor ✔ Node version is 8.9.3 info AppiumDoctor ✔ Xcode is installed at: /Library/Developer/CommandLineTools info AppiumDoctor ✔ Xcode Command Line Tools are installed. info AppiumDoctor ✔ DevToolsSecurity is enabled. info AppiumDoctor ✔ The Authorization DB is set up properly. WARN AppiumDoctor ✖ Carthage was NOTfound! info AppiumDoctor ✔ HOME issetto: /Users/chenwenguan WARN AppiumDoctor ✖ ANDROID_HOME isNOTset! WARN AppiumDoctor ✖ JAVA_HOME isNOTset! WARN AppiumDoctor ✖ adb could not be found because ANDROID_HOME isNOTset! WARN AppiumDoctor ✖ android could not be found because ANDROID_HOME isNOTset! WARN AppiumDoctor ✖ emulator could not be found because ANDROID_HOME isNOTset! WARN AppiumDoctor ✖ Bindirectoryfor $JAVA_HOME isnotset info AppiumDoctor ### Diagnostic completed, 7 fixes needed. ### info AppiumDoctor info AppiumDoctor ### Manual Fixes Needed ### info AppiumDoctor The configuration cannot be automatically fixed, please do the followingfirst: WARN AppiumDoctor - Please install Carthage. Visit https://github.com/Carthage/Carthage#installing-carthage for more information. WARN AppiumDoctor - Manually configure ANDROID_HOME. WARN AppiumDoctor - Manually configure JAVA_HOME. WARN AppiumDoctor - Manually configure ANDROID_HOME and run appium-doctor again. WARN AppiumDoctor - Add'$JAVA_HOME/bin'to your PATH environment info AppiumDoctor ### info AppiumDoctor info AppiumDoctor Bye! Run appium-doctor again whenallmanual fixes have been applied! info AppiumDoctor
1.8.0_60, x86_64:"Java SE 8"/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home
org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 1.41 seconds Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37' System info: host: 'wenguanchen-MacBook-Pro.local', ip: '30.85.214.6', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release' Driver info: io.appium.java_client.android.AndroidDriver Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=emulator-5554, fullReset=false, platform=LINUX, deviceUDID=emulator-5554, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=true, noReset=true, dontStopAppOnReset=true, deviceName=MuMu, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=4.4.4, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=4.4.4, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=true, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}] Session ID: 592813d6-7c6e-4a3c-8183-e5f93d1d3bf0 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204) at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:156) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599) at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27) at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1) at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1) at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:352) at org.openqa.selenium.remote.RemoteWebDriver.findElementByXPath(RemoteWebDriver.java:449) at io.appium.java_client.DefaultGenericMobileDriver.findElementByXPath(DefaultGenericMobileDriver.java:99) at io.appium.java_client.AppiumDriver.findElementByXPath(AppiumDriver.java:1) at io.appium.java_client.android.AndroidDriver.findElementByXPath(AndroidDriver.java:1) at org.openqa.selenium.By$ByXPath.findElement(By.java:357) at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:344) at io.appium.java_client.DefaultGenericMobileDriver.findElement(DefaultGenericMobileDriver.java:37) at io.appium.java_client.AppiumDriver.findElement(AppiumDriver.java:1) at io.appium.java_client.android.AndroidDriver.findElement(AndroidDriver.java:1) at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:335) at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:96) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document (Session info: webview=33.0.0.0) (Driver info: chromedriver=2.20.353124 (035346203162d32c80f1dce587c8154a1efa0c3b),platform=Mac OS X 10.13.2 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 2.41 seconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37' System info: host: 'wenguanchen-MacBook-Pro.local', ip: '30.85.214.81', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release' Driver info: io.appium.java_client.android.AndroidDriver Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=emulator-5554, fullReset=false, platform=LINUX, deviceUDID=emulator-5554, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=true, noReset=true, dontStopAppOnReset=true, deviceName=MuMu, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=4.4.4, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=4.4.4, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=true, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}] Session ID: b5e933e1-0ddf-421d-9144-e423a7bb25b1 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204) at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:156) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599) at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27) at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1) at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1) at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:268) at io.appium.java_client.DefaultGenericMobileElement.execute(DefaultGenericMobileElement.java:27) at io.appium.java_client.MobileElement.execute(MobileElement.java:1) at io.appium.java_client.android.AndroidElement.execute(AndroidElement.java:1) at org.openqa.selenium.remote.RemoteWebElement.getText(RemoteWebElement.java:152) at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:294) at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:110) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
org.openqa.selenium.remote.SessionNotFoundException: no such session (Driver info: chromedriver=2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4),platform=Mac OS X 10.13.2 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 14 milliseconds Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37' System info: host: 'wenguanchen-MacBook-Pro.local', ip: '192.168.1.102', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release' Driver info: io.appium.java_client.android.AndroidDriver Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=55CDU16C07009329, fullReset=false, platform=LINUX, deviceUDID=55CDU16C07009329, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=True, noReset=true, dontStopAppOnReset=true, deviceName=FRD-AL00, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=6.0, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=6.0, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=True, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}] Session ID: e2e50190-398b-4fa2-bc66-db1097201e3f at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204) at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:162) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599) at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27) at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:272) at org.openqa.selenium.remote.RemoteWebDriver.getPageSource(RemoteWebDriver.java:459) at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:238) at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:78) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
cd /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/node_modules/appium-chromedriver/chromedriver/mac/ open .
the default rule for AnyProxy. Anyproxy rules initialize finished, have fun! The WebSocket will not work properly in the https intercept mode :( fs.js:885 return binding.mkdir(pathModule._makeLong(path), ^ Error:EACCES: permission denied, mkdir '/Users/chenwenguan/.anyproxy/cache_r929590' at Object.fs.mkdirSync (fs.js:885:18) at Object.module.exports.generateCacheDir (/Users/chenwenguan/.nvm/versions/node/v8.9.3/lib/node_modules/anyproxy/lib/util.js:54:8) at new Recorder (/Users/chenwenguan/.nvm/versions/node/v8.9.3/lib/node_modules/anyproxy/lib/recorder.js:16:31) at /Users/chenwenguan/.nvm/versions/node/v8.9.3/lib/node_modules/anyproxy/proxy.js:116:43 at ChildProcess.exithandler (child_process.js:282:5) at emitTwo (events.js:126:13) at ChildProcess.emit (events.js:214:7) at maybeClose (internal/child_process.js:925:16) at Socket.stream.socket.on (internal/child_process.js:346:11) at emitOne (events.js:116:13)
Mac OS X上IntelliJ IDEA 13与Tomcat 8的Java Web开发环境搭建IntelliJ IDEA 15 创建maven项目MyBatis官网Intellij IDEA 使用教程HTML语言中括号(尖括号)的字符编码mac下mongodb的安装与配置mac下mongodb的安装和使用(使用终端操作)Intellij Mongo配置Java连接MongoDB进行增删改查IntelliJ IDEA手动配置连接MySQL数据库MongoDB中文教程MongoDB官方文档WebMagic 爬虫框架
对于 onDragEnd 方法来说,其实就是检测最后的结果了,刚才我们用 state 变量里面的 over 属性来代表是否拖动到目标位置上,这里我们也定义了另外的 dragged 属性来代表是否已经拖动完成,dragging 属性来代表是否正在拖动,所以整个方法的逻辑上是检测 over 属性,然后对 dragging、dragged 属性做赋值,然后做一些相应的提示,实现如下:
def drop_nonattrs(d, type): if not isinstance(d, dict): return d attrs_attrs = getattr(type, '__attrs_attrs__', None) if attrs_attrs is None: raise ValueError(f'type {type} isnotanattrsclass') attrs: Set[str] = {attr.name for attr in attrs_attrs} return {key: val for key, valin d.items()if key in attrs}
from typing import Set from attr import attrs, attrib import cattr
@attrs classPoint(object): x = attrib(type=int, default=0) y = attrib(type=int, default=0)
defdrop_nonattrs(d, type): ifnotisinstance(d, dict): returnd attrs_attrs = getattr(type, '__attrs_attrs__', None) ifattrs_attrsisNone: raiseValueError(f'type {type} isnot an attrs class') attrs: Set[str] = {attr.name for attr in attrs_attrs} return {key: val for key, val in d.items() if key in attrs}
import csv with open("employee.csv", mode="r") as csv_file: csv_reader = csv.DictReader(csv_file) line_count = 0 for row in csv_reader: if line_count == 0: print(f'Column names are {", ".join(row)}') line_count += 1 print(f'\\t{row["name"]} salary: {row["salary"]}' f'and was born in {row["birthday month"]}.') line_count += 1 print(f'Processed {line_count} lines.')
将代码分解为函数有助于使复杂的代码变的易于阅读和调试。 这里的代码在 with 语句中执行多项操作。为了提高可读性,您可以将带有 process salary 的代码从 CSV 文件中提取到另一个函数中,以降低出错的可能性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import csv with open("employee.csv", mode="r") as csv_file: csv_reader = csv.DictReader(csv_file) line_count = 0 process_salary(csv_reader)
defprocess_salary(csv_reader): """Process salary of user from csv file.""" for row in csv_reader: if line_count == 0: print(f'Column names are {", ".join(row)}') line_count += 1 print(f'\\t{row["name"]} salary: {row["salary"]}' f'and was born in {row["birthday month"]}.') line_count += 1 print(f'Processed {line_count} lines.')
defcall_weather_api(url, location): """Get the weather of specific location. Calling weather api to check for weather by using weather api and location. Make sure you provide city name only, country and county names won't be accepted and will throw exception if not found the city name. :param url:URL of the api to get weather. :type url: str :param location:Location of the city to get the weather. :type location: str :return: Give the weather information of given location. :rtype: str"""
说一下上面代码的注意点
第一行是函数或类的简要描述
每一行语句的末尾有一个句号
文档字符串中的简要描述和摘要之间有一行空白
如果使用 Python3.6 可以使用类型注解对上面的docstring以及参数的声明进行修改。
1 2 3 4 5 6 7 8
defcall_weather_api(url: str, location: str) -> str: """Get the weather of specific location. Calling weather api to check for weather by using weather api and location. Make sure you provide city name only, country and county names won't be accepted and will throw exception if not found the city name. """
"""This module contains all of the network related requests. This module will checkforall the exceptionswhile making the network calls andraiseexceptionsforanyunknown exception. Make sure that when you use this module, you handle these exceptionsinclient code as: NetworkError exceptionfor network calls. NetworkNotFound exceptionif network not found. """ import urllib3 import json
在为模块编写文档字符串时,应考虑执行以下操作:
对当前模块写一个简要的说明
如果想指定某些对读者有用的模块,如上面的代码,还可以添加异常信息,但是注意不要太详细。
1 2
NetworkError exception for network calls. NetworkNotFound exception if network not found.
classStudent: """Student class information. This class handle actions performed by a student. This class provides information about student full name, age, roll-number and other information. Usage: import student student = student.Student() student.get_name() >>> 678998 """ def__init__(self): pass
这个类 docstring 是多行的; 我们写了很多关于 Student 类的用法以及如何使用它。
函数的docstring
函数文档字符串可以写在函数之后,也可以写在函数的顶部。
1 2 3 4 5 6 7 8 9 10 11 12
def is_prime_number(number): """Checkfor prime number.
Check the given numberis prime number ornotby checking against all the numbers less the square root of given number.
:param number:Given numbertocheckfor prime :typenumber: int :return: Trueifnumberis prime otherwise False. :rtype: boolean """
如果我们使用类型注解对其进一步优化。
1 2 3 4 5 6 7
defis_prime_number(number: int)->bool: """Check for prime number. Check the given number is prime number or not by checking against all the numbers less the square root of given number. """
import pathlib now_path = pathlib.Path.cwd() from datetime import datetime time, file_path = max((f.stat().st_mtime, f) for f in now_path.iterdir()) print(datetime.fromtimestamp(time), file_path)
甚至可以使用类似的表达式获取上次修改的文件内容
1 2 3 4 5
import pathlib from datetime import datetime now_path =pathlib.Path.cwd() result = max((f.stat().st_mtime, f) for f in now_path.iterdir())[1] print(result.read_text())
.stat().st_mtime 会返回文件的时间戳,可以使用 datetime 或者 time 模块对时间格式进行进一步转换。
入职微软之后,这边大多数是使用 Windows 进行开发的,比如我的台式机是 Windows 的,还有一部分服务器是 Windows 的,当然 Linux 是也非常多。 很多情况下我是使用自己的 Mac 笔记本来远程连接我的 Windows 机器来开发的。比如如果我在工位上,我会用我的 Mac 连接两块显示屏,然后一种一块用来远程桌面连接我的 Windows 开发机,这样另外一块屏幕和 Mac 自带的屏幕就用来看文档或者使用 Teams 通讯等等。如果我回家了,我家里也是有两块屏,开上 VPN,照样用一块屏使用远程桌面,另外一块屏幕和 Mac 自带屏幕就可以做其他事情了。 这样就解决了一个问题:我的 Windows 基本上都是仅用作开发的,一块屏幕就开着一个 Visual Studio,其他的操作都会在 Mac 进行,比如查文档,发消息等等。这样我下班之后照样使用远程连接的方式来操作,和在公司就是一样的。这样就避免了一些软件的来回登录,比如如果我上班只用公司机器,下班了之后换了 Mac 还得切 Teams、切微信、切浏览器等等,还是很麻烦的,而且上班期间 Mac 就闲置了也不好。所以我就采取了这样的开发方案。
需求分析
有了这个情景,就引入了一个问题。开了一个远程桌面之后,我几乎一个屏幕都是被 Visual Studio 占据的,而远程桌面貌似只能开一个屏幕?如果我要再开一个终端窗口的话,那可能屏幕就不太够用了,或者它就得覆盖我的全屏 Visual Stuido。 另外我平时 Mac 终端软件都是使用 SSH 的,基本都是用来连 Linux 的,Windows 一般都是开远程桌面。但命令行这个情形的确让我头疼,让我感到不够爽,因为毕竟远程桌面之后,Windows 里面的操作都得挤在一个桌面里面操作了。当然可能能设置多个桌面,如果可以的话,麻烦大家告知一下谢谢。 所以解决的痛点在于:我要把一些操作尽量从 Windows 里面分离出来,例如终端软件,我能否在远程桌面外面操作,能否使用 SSH 来控制我的 Windows 机器。 好,有需求才有动力,说干就干。
如果是放开的,那么结果会提示 OpenSSH-Server-In-TCP这个状态是 enabled。 好了,完成如上操作之后我们就可以使用 SSH 来连接我们的 Windows 服务器了。
连接
连接非常简单了,用户名密码就是 Windows 的用户名和密码,使用 IP 地址链接即可。 比如我的 Windows 开发机的局域网 IP 为:10.172.134.88,那么就可以使用如下命令完成链接:
1
ssh user@10.172.134.88
然后输入密码,就连接成功了,和 Linux 的是一样的。 另外我自己现在 Mac 常用的 SSH 客户端工具有 Termius,可以多终端同步使用,非常方便,这里我只需要添加我的 Windows 机器就好了,如图所示: OK,以后就可以非常轻松地用 SSH 连接我的 Windows 服务器了,爽歪歪,上面的需求也成功解决。 以上便是使用 SSH 来连接 Windows 服务器的方法,如果大家有需求可以试试。
(function (a) { a.fn.typewriter = function () { this.each(function () { var d = a(this), c = d.html(), b = 0; d.html(""); var e = setInterval(function () { var f = c.substr(b, 1); if (f == "<") { b = c.indexOf(">", b) + 1 } else { b++ } d.html(c.substring(0, b) + (b & 1 ? "_" : "")); if (b >= c.length) { clearInterval(e) } }, 75) }); return this } })(jQuery);
这里可以看到,首先获取了页面代码区域的内容,然后通过 DOM 操作将代码先清空,然后利用 setInterval 方法设置一个定时器,定时间隔 75 毫秒,也就是说 75 毫秒循环调用一次。每调用一次,就会从原来的字符上多取一个字符,然后尾部拼接一个下划线就好了。
# You are the greatest love of my life. whileTrue: ifu.with(i): you = everything else: everything = u
这个代码的含义叫做“无论天涯海角,你都是我的一切。“,一个 while True 循环代表了永久。 这些代码其实都是在 HTML 代码中预定义好的,其中注释需要用 span 标签配以 comments 的 class 来修饰,缩进需要用 span 标签配以 placeholder 的 class 来修饰,例如:
1 2 3 4 5 6
<spanclass="comments"># You are the greatest love of my life.</span><br/> while <spanclass="keyword">True</span>:<br/> <spanclass="placeholder"></span><spanclass="keyword">if</span> u.with(i):<br/> <spanclass="placeholder"></span><spanclass="placeholder"></span>you = everything<br/> <spanclass="placeholder"></span><spanclass="keyword">else</span>:<br/> <spanclass="placeholder"></span><spanclass="placeholder"></span>everything = u<br/>
这里不同的格式用 span 的不同 class 来标识,空格缩进一个 placeholder 是两个空格,comments 代表注释格式,关键词使用 keyword 来标识。如果你需要自定义自己的内容,通过控制这些内容穿插写入就好了。
functiontimeElapse(c) { var e = Date(); var f = (Date.parse(e) - Date.parse(c)) / 1000; var g = Math.floor(f / (3600 * 24)); f = f % (3600 * 24); var b = Math.floor(f / 3600); if (b < 10) { b = "0" + b } f = f % 3600; var d = Math.floor(f / 60); if (d < 10) { d = "0" + d } f = f % 60; if (f < 10) { f = "0" + f } }
function getHeartPoint(c) { var b = c / Math.PI; var a = 19.5 * (16 * Math.pow(Math.sin(b), 3)); var d = -20 * (13 * Math.cos(b) - 5 * Math.cos(2 * b) - 2 * Math.cos(3 * b) - Math.cos(4 * b)); return newArray(offsetX + a, offsetY + d) }
作为一名程序员,能够利用好工具提高开发和工作效率是非常重要的。我个人使用的都是苹果系列产品,电脑为 MacBook Pro 15 寸,手机 iPhone 7P,另外还有一个 iPad Pro 和一副 Apple Watch。我一直觉得 Mac 是非常适合做程序开发的,它既有比较不错的页面,也有类 Unix 的操作系统,使得日常使用和程序开发都极其便利,另外由于苹果本身自有的 iCloud 机制,使用 Mac、iPhone、iPad 跨平台开发和工作也变得十分便利。
近期我又对自己的一些工具进行了整理,弃用了一些工具,新启用了一些工具。目的也只有一个,就是提高自己的工作和开发效率,让生活变得更美好。如果你也在用 Mac 开发,或者你也有使用 iPad、iPhone,下面我所总结的个人的一些工具或许能给你带来帮助。
快速导航
这是 Mac 上的一个工具,要说到提高效率,首推 Alfred,可以说是 Mac 必备软件,利用它我们可以快速地进行各种操作,大幅提高工作效率,如快速打开某个软件、快速打开某个链接、快速搜索某个文档,快速定位某个文件,快速查看本机 IP,快速定义某个色值,几乎我们能想到的都能对接实现。
其实 Mac 本身已经自带了软件搜索还有 Spotlight,但是其功能还是远远比不上 Alfred,有了它,所有的快捷操作几乎都能实现。
这些快速功能是怎么实现的呢?实际上是 Alfred 对接了很多 Workflow,我们可以使用 Workflow 方便地进行功能扩展,一些比较优秀的 Workflow 已经有人专门做过整理了,可以参见:https://github.com/zenorocha/alfred-workflows,大家可以安装自己所需要的 Workflow,大大提高效率。
复制粘贴
Mac 上默认只有一个粘贴板,当我们新复制了一段文字之后,如果我们想再找寻之前复制的历史记录就找不到了,这其实是很反人类的。
另外使用 Mac 和 iPhone、iPad 之间也可以相互之间复制粘贴,可以在一台 Apple 设备上拷贝文本、图像、照片和视频,然后在另一台 Apple 设备上粘贴该内容。例如,可以拷贝在 Mac 上浏览网页时发现的食谱,然后将其粘贴到附近 iPhone 上“备忘录”中的购物清单。这是在 macOS Sierra 版本之后出来的功能,若要使用需要确保 Mac 的版本是 Sierra 及以后。若要使用,几个设备必须满足“连续互通”系统要求。它们还必须在“系统偏好设置”(在 Mac 上)和“设置”(在 iOS 设备上)中打开 Wi-Fi、蓝牙和 Handoff,另外必须在所有设备上使用同一 Apple ID登录 iCloud。
言归正传,既然谈到笔记和写作。我的笔记本是 Mac,之前几乎所有的笔记,包括写书,都几乎是在 Mac 上完成的,但是确实有的时候是不方便的。比如 Mac 不在身边或者想用 iPhone 或者 iPad 来写点东西的时候,一个需要解决的问题就是云同步问题。有了云同步,我们如果在电脑上写了一部分内容,接着切换了另一台台式机,或者切换了手机的时候,照样能够接着在原来的基础上写,非常方便。
所谓爬虫的智能化解析,顾名思义就是不再需要我们针对某一些页面来专门写提取规则了,我们可以利用一些算法来计算出来页面特定元素的位置和提取路径。比如一个页面中的一篇文章,我们可以通过算法计算出来,它的标题应该是什么,正文应该是哪部分区域,发布时间是什么等等。 其实智能化解析是非常难的一项任务,比如说你给人看一个网页的一篇文章,人可以迅速找到这篇文章的标题是什么,发布时间是什么,正文是哪一块,或者哪一块是广告位,哪一块是导航栏。但给机器来识别的话,它面临的是什么?仅仅是一系列的 HTML 代码而已。那究竟机器是怎么做到智能化提取的呢?其实这里面融合了多方面的信息。
比如标题。一般它的字号是比较大的,而且长度不长,位置一般都在页面上方,而且大部分情况下它应该和 title 标签里的内容是一致的。
比如正文。它的内容一般是最多的,而且会包含多个段落 p 或者图片 img 标签,另外它的宽度一般可能会占用到页面的三分之二区域,并且密度(字数除以标签数量)会比较大。
doc = etree.HTML(con) shops = doc.xpath('//div[@id="shop-all-list"]/ul/li') for shop in shops: # 店名 name = shop.xpath('.//div[@class="tit"]/a')[0].attrib["title"] print name comment_num = 0
comment_and_price_datas = shop.xpath('.//div[@class="comment"]') for comment_and_price_data in comment_and_price_datas: _comment_data = comment_and_price_data.xpath('a[@class="review-num"]/b/node()') # 遍历每一个node,这里node的类型不同,分别有etree._ElementStringResult(字符),etree._Element(元素),etree._ElementUnicodeResult(字符) for _node in _comment_data: # 如果是字符,则直接取出 if isinstance(_node, etree._ElementStringResult): comment_num = comment_num * 10 + int(_node) else: # 如果是span类型,则要去找数据 # span class的attr span_class_attr_name = _node.attrib["class"] # 偏移量,以及所处的段 offset, position = css_and_px_dict[span_class_attr_name] index = abs(int(float(offset) )) position = abs(int(float(position))) # 判断 for key, value in svg_threshold_and_int_dict.iteritems(): if position in value: threshold = int(math.ceil(index/12)) number = int(key[threshold]) comment_num = comment_num * 10 + number print comment_num
defget_public_ip_address(): """ 获取IP和实例ID :return: {实例ID: ip} """ response = ec2.describe_instances() reservations = response.get('Reservations') instances = [i.get('Instances')[0] for i in reservations] instance_id_public_ip_address = {i.get('InstanceId'): i.get('PublicIpAddress') for i in instances} return instance_id_public_ip_address
defreboot_ec2(ip): """重启实例 :param ip: :return: """ instance_id_public_ip_address = get_public_ip_address() instance_id = instance_id_public_ip_address.get(ip) try: ec2.reboot_instances(InstanceIds=[instance_id], DryRun=True) except ClientError as e: if'DryRunOperation'notin str(e): print("You don't have permission to reboot instances.") raise
首选我们梳理一下 Linux 下的用户、用户组、文件权限等基本知识,然后后面通过一个案例来实际演示一下权限设置的一些操作。 首先 Linux 系统中,是有用户和用户组的概念的,用户就是身份的象征,我们必须以某一个用户身份来操作一个系统,实际上这就对应着我们登录系统时的账号。而用户组就是一些用户的集合,我们可以通过用户组来划分和统一管理某些用户。 比如我要在微信发一条朋友圈,我只想给我的亲人们看,难道我发的时候还要一个个去勾选所有的人?这未免太麻烦了。为了解决这问题,微信里面就有了标签的概念,我们可以提前给好友以标签的方式分类,发的时候直接勾选某个标签就好了,简单高效。实际上这就是用户组的概念,我们可以将某些人进行分组和归类,到时候只需要指定类别或组别就可以了,而不用一个个人去对号入座,从而节省了大量时间。 在 Linux 中,一个用户是可以属于多个组的,一个组也是可以包含多个用户的,下面我以一台 Ubuntu Linux 为例来演示一下相关的命令和操作。
Adding user `cqc' ... Adding new group `cqc' (1002) ... Adding new user `cqc' (1002) with group `cqc'... Creating home directory `/home/cqc' ... Copying files from `/etc/skel'... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for cqc Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n]
id cqc uid=1002(cqc) gid=1002(cqc) groups=1002(cqc),27(sudo),1003(lab) id lbd uid=1004(lbd) gid=1005(lbd) groups=1005(lbd),1003(lab) id slb uid=1003(slb) gid=1004(slb) groups=1004(slb)
Welcome to fdisk (util-linux 2.27.1). Changes will remain in memory only, until you decide to write them. Be careful before using the write command.
Device does not contain a recognized partition table. Created a new DOS disklabel with disk identifier 0xc305fe54.
Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1): First sector (2048-2145386495, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-2145386495, default 2145386495):
Created a new partition 1 of type 'Linux'and of size 1023 GiB.
然后使用 p 打印分区表并使用 w 将表写入磁盘,然后退出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Command (m for help): p Disk /dev/sdc: 1023 GiB, 1098437885952bytes, 2145386496 sectors Units: sectors of1 * 512 = 512bytes Sector size (logical/physical): 512bytes / 512bytes I/O size (minimum/optimal): 512bytes / 512bytes Disklabel type: dos Disk identifier: 0xc305fe54
Device Boot StartEnd Sectors SizeIdType /dev/sdc1 2048214538649521453844481023G 83 Linux
Command (m forhelp): w The partitiontable has been altered. Calling ioctl() to re-readpartition table. Syncing disks.
阻塞状态指程序未得到所需计算资源时被挂起的状态。程序在等待某个操作完成期间,自身无法继续干别的事情,则称该程序在该操作上是阻塞的。 常见的阻塞形式有:网络 I/O 阻塞、磁盘 I/O 阻塞、用户输入阻塞等。阻塞是无处不在的,包括 CPU 切换上下文时,所有的进程都无法真正干事情,它们也会被阻塞。如果是多核 CPU 则正在执行上下文切换操作的核不可被利用。
Coroutine: <coroutine object execute at 0x10e0f7830> After calling execute Task: <Task pending coro=<execute() running at demo.py:4>> Number: 1 Task: <Task finished coro=<execute() done, defined at demo.py:4> result=1> After calling loop
Coroutine: <coroutine object execute at 0x10aa33830> After calling execute Task: <Task pending coro=<execute() running at demo.py:4>> Number: 1 Task: <Task finished coro=<execute() done, defined at demo.py:4> result=1> After calling loop
发现其效果都是一样的。
3.2 绑定回调
另外我们也可以为某个 task 绑定一个回调方法,来看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import asyncio import requests
async def request(): url = 'https://www.baidu.com' status = requests.get(url) return status
Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Cost time:15.049368143081665
Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Cost time:15.048935890197754 Task exception was never retrieved future: <Task finished coro=<request() done, defined at demo.py:7> exception=TypeError("object Response can't be used in 'await' expression",)> Traceback (most recent call last): File "demo.py", line 10, in request status = await requests.get(url) TypeError: object Response can't be used in 'await' expression
Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Cost time:15.134317874908447
Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Waiting forhttp://127.0.0.1:5000 Get response from http://127.0.0.1:5000 Result: Hello! Get response from http://127.0.0.1:5000 Result: Hello! Get response from http://127.0.0.1:5000 Result: Hello! Get response from http://127.0.0.1:5000 Result: Hello! Get response from http://127.0.0.1:5000 Result: Hello! Cost time:3.0199508666992188
一些日常工具在这里我就不一一列举了,大部分使用 Mac 的小伙伴都会安装,比如 QQ、微信、Chrome 浏览器、网易云音乐、迅雷等等,这些在 Windows 上也几乎都是必备软件,这里就不再展开说明了。
效率工具
效率工具顾名思义,可以方便和简化 Mac 的操作,提高生产工作效率的工具,下面推荐几款我比较常用的。
Alfred
首推 Alfred,可以说是 Mac 必备软件,利用它我们可以快速地进行各种操作,大幅提高工作效率,如快速打开某个软件、快速打开某个链接、快速搜索某个文档,快速定位某个文件,快速查看本机 IP,快速定义某个色值,几乎你能想到的都能对接实现。 这些快速功能是怎么实现的呢?实际上是 Alfred 对接了很多 Workflow,我们可以使用 Workflow 方便地进行功能扩展,一些比较优秀的 Workflow 已经有人专门做过整理了,可以参见:https://github.com/zenorocha/alfred-workflows。 推荐指数:★★★★★
Todoist
大家肯定也在使用各种 Todo List 的软件,这种软件其实也是五花八门,经过我本人试用,我觉得 Todoist 这款软件是最方便的。 它支持各种类型的任务定制,还可以设置分组、优先级、Deadline、执行人员、提醒、协作、效率统计等功能。另外它的各个平台支持真是异常地全啊,网页、PC、移动端就不用说了,都必须有的,另外它还有浏览器插件版、电邮版、可穿戴设备(如 Apple Watch、Google Wear)版,另外他还可以和 Mac 的日历事件进行同步,日历添加的事件也会自动添加到 Todoist 里面,非常方便,是目前我体验过的最好用的一款。 这款软件个人推荐购买专业版解锁全部功能,一个月 3 刀,但个人觉得确实非常值。 推荐指数:★★★★☆
Paste
Mac 上默认只有一个粘贴板,当我们新复制了一段文字之后,如果我们想再找寻之前复制的历史记录就找不到了,这其实是很反人类的。 好在 Paste 这款软件帮我们解决了这个问题,它可以保存我们粘贴板的历史记录,等需要粘贴某个内容的时候只需要呼出 Paste 历史粘贴板,然后选择某个特定的内容粘贴就好了,另外它还支持文本格式调整粘贴板分类和搜索,还可以支持快速便捷粘贴。有了它,妈妈再也不用担心我的粘贴板丢失了! 推荐指数:★★★★★
Synergy
工作时我会使用公司的台式机,是 Windows 系统,另外自己的个人笔记本 Mac 也会放在旁边,两台 PC 有时候会交替使用,但是我总不能配两套键盘和鼠标吧,这样就显得累赘了,而且也没那么多地方放啊。 有了 Synergy,我们可以将两台 PC 关联,实现键盘鼠标共享。我们可以使用一套键盘和鼠标来操作两台 PC,注意这是两个完全独立的 PC,各自有各自的屏幕和系统,使用 Synergy 我们可以做到一套键鼠同时控制两台电脑,鼠标可以直接从一台电脑的屏幕滑动到另一台电脑屏幕上,同时键盘、粘贴板也都是共享的。 设想这么个情景,我在我的台式机 Windows 上打开了一个页面,需要让我输入一个很长的序列号,而这个序列号又恰巧存在 Mac 上,这时如果有了 Synergy 将二者关联,我们只需要把鼠标从 Windows 的屏幕上直接滑动到 Mac 的屏幕上,选中序列号,然后键盘按下复制的快捷键,然后再把鼠标移回 Windows,粘贴即可,一气呵成。而不必再想办法发消息传输了,大大提高效率。 推荐指数:★★★★
用了 Mac,我们在使用移动硬盘的时候可能会遇到一个无法传输数据(如拷贝文件)的问题,这是因为部分移动硬盘是 NTFS 格式的,而 Mac 的磁盘不是这个格式,因此就会导致二者之间无法拷贝文件。有一个解决方法就是使用 Tuxera NTFS For Mac,有了它,我们就可以比较顺利地拷贝文件了。 另外还有其他品牌的 NTFS For Mac 软件,也可以尝试使用一下。 推荐指数:★★★★☆
VMware、Parallels Desktop
用了 Mac 之后,难免会有些情况下也还会不得不使用 Windows,毕竟很多软件可能只有 Windows 版本,但用 Mac 我就不推荐装双系统了,直接装虚拟机就好了,Mac 上虚拟机软件有两款比较好用,一个就是著名的 VMware,另一个就是 Parallels Desktop,这两款我都使用过,觉得都非常不错,现在用的是 VMware。 推荐指数:★★★★☆
CleanMyMac
很多时候用着用着磁盘就不够用了,如果你的 Mac 硬盘是 512GB 的倒还好,256GB 的你就得多注意一下了,另外 1T 定制版土豪请绕道,这款软件不适合你。 CleanMyMac 可以非常方便地帮助我们扫描缓存、大文件、废纸篓、残留项等内容,清理这些内容之后我们可以节省很多硬盘空间,另外它还支持软件卸载和残留清扫功能,可以帮我们非常干净地移除 Mac 中的软件,目前应该是出到第三版了,非常推荐。 推荐指数:★★★★☆
编辑器
既然做程序开发嘛,不配置好自己的开发环境怎么行,下面推荐一下我平常使用的开发软件。
JetBrains
我目前使用的 IDE 是 JetBrains 全家桶,目前我编写 Python 比较多,所以主要使用 PyCharm,另外写前端的时候也会使用 WebStorm,写 Java 就用 IntelliJ IDEA,C、C++ 用 CLion,PHP 的话就用 PhpStorm,Ruby 的话就用 RubyMine,其他的语言用的就少了,就没有装了。 当然有的小伙伴会说 JetBrains 系列的 IDE 需要购买啊?我只想说,国人的力量是无穷的,在网上其实可以搜到各种破解方法,如 License Server 验证,你能搜到各种五花八门的 License Server。另外 JetBrains 还有专门的 Educational Programs,可以来这里申请:https://www.jetbrains.com/education/programs/?fromMenu,学生、老师或教育工作者可以使用学校的 edu 邮箱申请免费的 License,如果你还是学生的话,那么申请是十分方便的,因为我还是个学生,我目前就在使用学生套餐,当然如果你已经工作的话也可以向正在上学的弟弟妹妹们借一下嘛。 总之我个人比较喜欢 JetBrains 全家桶,不论是页面风格还是开发习惯我都比较喜欢,推荐使用。 推荐指数:★★★★☆
对于开发者来说,这个软件几乎是 Mac 上必备的一个软件,它的官方简介就是 “The missing package manager for macOS”,算是 Mac 上的一个软件包平台,它里面包含着非常多的 Mac 开发软件包,比如 Python、PHP、Redis、MySQL、RabbitMQ、HBase 等等,几乎你能想到的开发软件都集成在里面了,堪称神器! 它的安装也非常简单,参见这里:https://brew.sh/,另外 HomeBrew 也有对应的图形界面,叫做 CakeBrew,如果不喜欢命令行操作的话可以使用 CakeBrew 来代替。 推荐指数:★★★★★
import gensim import jieba import numpy as np from scipy.linalg import norm
model_file = './word2vec/news_12g_baidubaike_20g_novel_90g_embedding_64.bin' model = gensim.models.KeyedVectors.load_word2vec_format(model_file, binary=True)
defvector_similarity(s1, s2): defsentence_vector(s): words = jieba.lcut(s) v = np.zeros(64) for word in words: v += model[word] v /= len(words) return v v1, v2 = sentence_vector(s1), sentence_vector(s2) return np.dot(v1, v2) / (norm(v1) * norm(v2))
# If these values are missing, it means we want to use the defaults. optional = { # TODO: Use custom prefixes for this settings to note that are # specific to scrapy-redis. 'queue_key': 'SCHEDULER_QUEUE_KEY', 'queue_cls': 'SCHEDULER_QUEUE_CLASS', 'dupefilter_key': 'SCHEDULER_DUPEFILTER_KEY', # We use the default setting name to keep compatibility. 'dupefilter_cls': 'DUPEFILTER_CLASS', 'serializer': 'SCHEDULER_SERIALIZER', } # 从setting中获取配置组装成dict(具体获取那些配置是optional字典中key) for name, setting_name in optional.items(): val = settings.get(setting_name) if val: kwargs[name] = val
# Support serializer as a path to a module. if isinstance(kwargs.get('serializer'), six.string_types): kwargs['serializer'] = importlib.import_module(kwargs['serializer']) # 或得一个Redis连接 server = connection.from_settings(settings) # Ensure the connection is working. server.ping()
return cls(server=server, **kwargs)
@classmethod def from_crawler(cls, crawler): instance = cls.from_settings(crawler.settings) # FIXME: for now, stats are only supported from this constructor instance.stats = crawler.stats return instance
def open(self, spider): self.spider = spider
try: # 根据self.queue_cls这个可以导入的类 实例化一个队列 self.queue = load_object(self.queue_cls)( server=self.server, spider=spider, key=self.queue_key % {'spider': spider.name}, serializer=self.serializer, ) except TypeError as e: raise ValueError("Failed to instantiate queue class '%s': %s", self.queue_cls, e)
if self.flush_on_start: self.flush() # notice if there are requests already in the queue to resume the crawl if len(self.queue): spider.log("Resuming crawl (%d requests scheduled)" % len(self.queue))
# 在Redis有序集合中数值越小优先级越高(就是会被放在顶层)所以这个位置是取得 相反数 score = -request.priority # We don't use zadd method as the order of arguments change depending on # whether the class is Redis or StrictRedis, and the option of using # kwargs only accepts strings, not bytes. # ZADD 是添加进有序集合 self.server.execute_command('ZADD', self.key, score, data)
defpop(self, timeout=0): """ Pop a request timeout not support in this queue class 有序集合不支持超时所以就木有使用timeout了 这个timeout就是挂羊头卖狗肉 """ """从有序集合中取出一个Request""" # use atomic range/remove using multi/exec """使用multi的原因是为了将获取Request和删除Request合并成一个操作(原子性的)在获取到一个元素之后 删除它,因为有序集合 不像list 有pop 这种方式啊""" pipe = self.server.pipeline() pipe.multi() # 取出 顶层第一个 # zrange :返回有序集 key 中,指定区间内的成员。0,0 就是第一个了 # zremrangebyrank:移除有序集 key 中,指定排名(rank)区间内的所有成员 0,0也就是第一个了 # 更多请参考Redis官方文档 pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0) results, count = pipe.execute() if results: return self._decode_request(results[0])
logger.info('This is a log info') logger.debug('Debugging') logger.warning('Warning exists') logger.info('Finish')
在这里我们首先引入了 logging 模块,然后进行了一下基本的配置,这里通过 basicConfig 配置了 level 信息和 format 信息,这里 level 配置为 INFO 信息,即只输出 INFO 级别的信息,另外这里指定了 format 格式的字符串,包括 asctime、name、levelname、message 四个内容,分别代表运行时间、模块名称、日志级别、日志内容,这样输出内容便是这四者组合而成的内容了,这就是 logging 的全局配置。 接下来声明了一个 Logger 对象,它就是日志输出的主类,调用对象的 info() 方法就可以输出 INFO 级别的日志信息,调用 debug() 方法就可以输出 DEBUG 级别的日志信息,非常方便。在初始化的时候我们传入了模块的名称,这里直接使用 name 来代替了,就是模块的名称,如果直接运行这个脚本的话就是 main,如果是 import 的模块的话就是被引入模块的名称,这个变量在不同的模块中的名字是不同的,所以一般使用 name 来表示就好了,再接下来输出了四条日志信息,其中有两条 INFO、一条 WARNING、一条 DEBUG 信息,我们看下输出结果:
1 2 3
2018-06-0313:42:43,526 - __main__ - INFO - This is a log info 2018-06-0313:42:43,526 - __main__ - WARNING - Warning exists 2018-06-0313:42:43,526 - __main__ - INFO - Finish
2018-06-0314:53:36,467 - __main__ - INFO - This is a log info 2018-06-0314:53:36,468 - __main__ - WARNING - Warning exists 2018-06-0314:53:36,468 - __main__ - INFO - Finish
2018-06-0315:13:44,895 - __main__ - INFO - This is a log info 2018-06-0315:13:44,947 - __main__ - WARNING - Warning exists 2018-06-0315:13:44,949 - __main__ - INFO - Finish
2018-06-0316:55:56,259 - main - INFO - Main Info 2018-06-0316:55:56,259 - main - ERROR - Main Error 2018-06-0316:55:56,259 - main.core - INFO - Core Info 2018-06-0316:55:56,259 - main.core - ERROR - Core Error
try: result = 5 / 0 except Exception as e: # bad logging.error('Error: %s', e) # good logging.error('Error', exc_info=True) # good logging.exception('Error')