前几天买了云服务器,这几天安装个python3环境,跑个selenium
1 一个结合文件发送,命令行,监控一体化的链接工具支持跨平台 http://www.hostbuf.com/?install_fs
按照顺序双击即可
2 命令行安装python(root身份),命令完全兼容centos7.6 https://www.linuxidc.com/Linux/2018-07/153286.htm
3 安装虚拟环境,此处有些小插曲,记录如下
安装虚拟机必要环境
可以先更新下pip
pip install --upgrade pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper
安装结束就启动虚拟环境(如果不行可以重复操作)
source virtualenvwrapper.sh
创建虚拟环境(py3_flask是虚拟环境名字)
mkvirtualenv -p python3 py3_flask
查看虚拟环境(可用tab按钮,快捷方便)
workon py3_flask
退出虚拟环境
deactivate
删除虚拟环境(先退出才能删除)
rmvirtualenv py3_flask
查看虚拟环境新安装的包
pip freeze
4 这几天用本地软件跑selenium,网络不稳定,我都忘了我还有个云主机闲着。今天部署下
安装chrome
yum install https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
查看版本
在上面有 83.0.4103.116-1
下载chromedriver找对应版本 https://npm.taobao.org/mirrors/chromedriver/
wget http://npm.taobao.org/mirrors/chromedriver/83.0.4103.39/chromedriver_linux64.zip
chmod +x /home/mysoft/spyder/chromedriver
编辑py文件 此处给出一个可以正常运行的文件示例
#! /usr/bin/python3 from selenium import webdriver chrome_options = webdriver.ChromeOptions() # 不加载图片,加快访问速度 chrome_options.add_experimental_option("prefs", {"profile.mamaged_default_content_settings.images": 2}) # 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) chrome_options.add_argument('--headless') chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-gpu') chrome_options.add_argument('--disable-dev-shm-usage') browser = webdriver.Chrome(options=chrome_options) url = "https://www.baidu.com/" browser.get(url) html = browser.find_element_by_xpath("//*").get_attribute("outerHTML") print(html) print("-----------------------------------")
记录几个报错
chrome not run,,,,,, 可能是chromeoption设置不好,参照以上代码
No such file or directory xxxx 可能是没有权限 chmod u+x xxxx
如果还有其他不可描述的错误。比如语法没错,但是就是通不过,可能是python缩进有问题,花费两三分钟统一下格式
查看正在运行的python程序 ps -ef | grep python
找到进程id 杀死进程 kill -9 4394
selenium的键盘按键的正确用法 https://www.jianshu.com/p/56e1295b031f
eg:driver.find_element_by_id('DomainName').send_keys("{ENTER}")
记录几个xpath的操作
driver.find_element_by_id('DomainName').clear() time.sleep(0.2 * random.random()) driver.find_element_by_id('DomainName').send_keys("%s.com\n" % (li)) driver.find_element_by_id('DomainName').send_keys("{ENTER}") WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CLASS_NAME, 'search-write-btn'))) # tag_element = driver.find_element_by_class_name('search-write-btn') # ActionChains(driver).move_to_element(tag_element).perform().click() time.sleep(0.5 + 0.2 * random.random()) # driver.find_element_by_class_name('search-write-btn').click() # js ="document.getElementByClass('search-write-btn').click()" # js点击元素 # driver.execute_script(js) # 显示等待知道元素出现 WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CLASS_NAME, 'search-write-btn'))) html = driver.find_element_by_xpath("//*").get_attribute("outerHTML") write_to_html(str(i),html) result = driver.find_element_by_xpath("//*[contains(text(), '未被注册')]")
记录几个刷新界面的方法 https://www.cnblogs.com/MasterMonkInTemple/p/4097512.html
在linux编程中,如果文件中用到当前目录,则应该cd 到指定目录下,不然程序会报路径找不到错误,另一种解决方式是在程序中获取当前路径,然后拼接
python中出现invalid syntax报错的几种原因
缩进不对,或者符号错误(某些无法描述的错误就是缩进不对)
目前还有一个奇葩错误
list' object has no attribute 'get'
问题是我用的是drivert.get(url) 并不是获取elements元素导致的错误,
解决方法:将except中异常处理的代码(driver.get(url))想办法放到try中。
某次点击按钮无法使用,解决办法:在输入框后面拼接字符串"\n" 不知为何,在win中运行很好,但是在linux下各种报错。
注意下try except用法,注意可能是哪个地方出错了,
注意只对绝对有异常的地方进行try 。。。。except pass。。。。。。。可以选择什么也不处理
(比如某元素找不到,程序会报异常进而终止运行,这时候必须try上,保证程序整体运行)
注意如果有需要,可多层嵌套try except 对于不同层侧的异常区别对待
注意 if a and b:pass else: 与 if a: if b:pass (a)else: 是不一样的
注意 如果比较某字符串相等,从字面看绝对没有不一样的,但是就是不相等,可能是utf8自动加载的字符bom等,处理方式编码方式修改为utf8-mas,或者,首行空一行
2020.07.13 18:00 继续记录bug
1 异常报错,网上说是文件开头没写# -*- coding: utf-8 -*-等编写方法导致错误,但是我修改了编码之后还是错,加上还是错,修改了编译环境还是错,修改了运行环境还是错
解决办法:可能是pycharm开的编译运行环境太杂乱导致,先关闭所有项目,然后关闭pycharm,然后关闭重启pycharm,,,,,,好了
2 driver获取元素必须先获取element,在获取信息,不方便,可以用lxml解析,具体步骤,lxml只识别文本,得先将driver转成str格式才能被解析
3 可以先用try xpath插件写语法,进行检测,推荐火狐浏览器安装try xpath,其他的我找不着
https://www.w3school.com.cn/xpath/xpath_syntax.asp
from lxml import etree
time.sleep(0.1 + 0.5 * random.random()) html = driver.find_element_by_xpath("//*").get_attribute("outerHTML") html = etree.HTML(html) urls = html.xpath("//*[@class='listBox2']/ul/li//h3/a/@href") texts = html.xpath("//*[@class='listBox2']/ul/li//h3/a/text()")
4 推荐个driver的写法,配置option使得可以无界面获取数据
def get_driver(): chrome_options = webdriver.ChromeOptions() # 不加载图片,加快访问速度 chrome_options.add_experimental_option("prefs", {"profile.mamaged_default_content_settings.images": 2}) # 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) chrome_options.add_argument('--headless') chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-gpu') chrome_options.add_argument('--disable-dev-shm-usage') #browser = webdriver.Chrome(executable_path="../chromedriver",options=chrome_options)#无界面的selenium browser = webdriver.Chrome(executable_path="../chromedriver")#有界面的selenium return browser
5 计算程序执行时间time.time()以秒为单位
6 复杂字符替换还是使用正则比较好 推荐菜鸟教程 https://blog.csdn.net/qq_20412595/article/details/82633501 group讲解比较详细
text = re.search(r"([0-9]*[-]?[0-9]*)(\S+)(大学排名|大学排行榜)", text_lis[i]).group(2)
url = re.search(r"../(\S+)", url_lis[i]).group(1)
7 找当前页面url driver.current_url 判断当前页和下一页是否在同一个页面判断跳转是否成功
8 xpath中contains可以配合属性和text()使用,,注意加点异常捕获
try: driver.find_element_by_xpath("//*[contains(@src, 'narNext.gif')]").click() except: pass
9 数组连接可以用join
f.write(",".join(li))
10 正则表达式筛选中文,用group好点
text = "全国服装设计专业" re.search(r"(全国|)(\S+)",text).group(2)
11 driver.get(url)即在原来的地址栏输入地址, driver.execute_script(url)即新开一个窗口输入地址 刷新页面driver.refresh() 获取当前页面url driver.current_url
12 driver切换窗口
#切换窗口到最近打开的那一个(实际是切换句柄) driver.switch_to.window(driver.window_handles[-1]) # 等待窗口全部打开 webDriverWait(driver, 10).until(EC.new_window_is_opened(driver.window_handles))
# 创建一个新窗口
driver.execute_script("https://baike.baidu.com/")
13 记得在每次界面有刷新之后延时一小会儿,我这边服务器慢,我延时3-3.6s左右,具体情况,具体分析
14 打开一个新的界面之后记得先切换窗口句柄,不然不可能获取到指定页面的元素
15 获取元素可能性很多,注意try except的嵌套使用
16 重新修改print方法实现log日志 https://www.jianshu.com/p/d485bb30c5bb (反正我一般不会用这种) (下面链接时我见过说log日志最简洁的一篇博客)
https://mp.weixin.qq.com/s?src=11×tamp=1594766431&ver=2461&signature=r5OfNsXrVLPm3ipxK0wbeoc2p4NPr7o9JQKoQgyRo8cuxcoMzYLX7zobIMpBg4q2hcrixANsnuhLcPl50smoCn0fKAbL0j7XiPVZusvDKY4D3OTImp41I50pUxFuX-vB&new=1
https://www.jb51.net/article/165167.htm
https://www.cnblogs.com/itBlogToYpl/p/12753067.html
17 我参考别人的log日志封装了一个日志类
https://blog.csdn.net/weixin_33991727/article/details/93362394
下面是我自己封装的log类,可以实现不同级别的log输出到不同的日志中
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
该日志类可以把不同级别的日志输出到不同的日志文件中
'''
import os
import time
import logging
import inspect
handlers = {logging.NOTSET: "./tmp/TNLOG-notset.log",
logging.DEBUG: "./tmp/TNLOG-debug.log",
logging.INFO: "./tmp/TNLOG-info.log",
logging.WARNING: "./tmp/TNLOG-warning.log",
logging.ERROR: "./tmp/TNLOG-error.log",
logging.CRITICAL: "./tmp/TNLOG-critical.log"}
mylog = {
"info":"./tmp/TNLOG-mylog.log"
}
def createFile(filename):
path = filename[0:filename.rfind('/')]
if not os.path.isdir(path):
os.makedirs(path)
if not os.path.isfile(filename):
# 创建并打开一个新文件
fd = open(filename, mode='w', encoding='utf-8')
fd.close()
def createHandlers():
logLevels = handlers.keys()
for level in logLevels:
path = os.path.abspath(handlers[level])
createFile(handlers[level])
handlers[level] = logging.FileHandler(path)
myls = mylog.keys()
for myl in myls:
createFile(mylog[myl])
class TNLog(object):
def printfNow(self):
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
def __init__(self, level=logging.NOTSET):
# 加载模块时创建全局变量
self.__loggers = {}
logLevels = handlers.keys()
for level in logLevels:
logger = logging.getLogger(str(level))
# 如果不指定level,获得的handler似乎是同一个handler?
logger.addHandler(handlers[level])
logger.setLevel(level)
self.__loggers.update({level: logger})
def getLogMessage(self, level, message):
frame, filename, lineNo, functionName, code, unknowField = inspect.stack()[2]
'''日志格式:[时间] [类型] [记录代码] 信息'''
return "[%s] [%s] [%s - %s] %s" % (self.printfNow(), level, lineNo, functionName, message)
def info(self, message):
message = self.getLogMessage("info", message)
self.__loggers[logging.INFO].info(message)
def error(self, message):
message = self.getLogMessage("error", message)
self.__loggers[logging.ERROR].error(message)
def warning(self, message):
message = self.getLogMessage("warning", message)
self.__loggers[logging.WARNING].warning(message)
def debug(self, message):
message = self.getLogMessage("debug", message)
self.__loggers[logging.DEBUG].debug(message)
def critical(self, message):
message = self.getLogMessage("critical", message)
self.__loggers[logging.CRITICAL].critical(message)
def mymsg(self, message):
message = "[%s] %s\n" % (self.printfNow(), message)
path = mylog["info"]
with open(path, "a+", encoding='utf-8') as f:
f.write(message)
def logger():
createHandlers()
logger = TNLog()
return logger
if __name__ == "__main__":
logger = logger()
logger.debug("debug")
logger.info("info")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
s = "检测结果 False 当前进度 5.597125720054636% 执行个数 1885 异常值个数 2726 当前检测 bgu "
logger.mymsg(s)
logger.mymsg(s)
logger.mymsg(s)
18 之前运行程序一直都是在前台,长循环程序总是莫名其妙退出,通过尝试,可以用shell脚本写个小脚本,省略那些麻烦的操作,执行某命令可以使得程序需后台运行,
这样就算本地断网也没关系啦。程序命名为xxx.sh
#!/bin/bash # Your Answer # filename: cd.sh # chmod +x cd.sh # ./cd.sh /var/www cd /home/mysoft/spyder/choosecom/try32/ nohup python3 /home/mysoft/spyder/choosecom/try32/try3.py > ./run.log 2>&1 &
2020 07 18
19 今天继续爬虫,遇到一个问题,我xpath语法没错,在firefox上利用try xpath也可以获取,但是就是匹配不到,经过检查发现在模拟网页跳转之后,网页指针没有定位到当前页,导致页面元素获取不到。
因此在以后每次获取新页面并且要在新页面进行操作时,或者在当前页面关闭之后,可以加上
driver.switch_to.window(driver.window_handles[-1])
driver.close() driver.switch_to.window(driver.window_handles[-1])
20 经过摸索,我发现driver类似于单例模式,全局如果只是get一个出来,那全局都只会使用者一个driver,因此如果关闭当前页面一定要记得加上这么一句,反正不会错
driver.switch_to.window(driver.window_handles[-1])
21 记录一个/引发的血案。今天爬取学校数据意外发现学校名称部分是错误的,这个错误刚开始没有发现,知道抓取学校信息时候,在控制台看到这个问题。也就是说,之前爬取的数据都是错误的,必须有重新抓。
解决办法,因为学校这一栏标签内部还有标签,我在爬取的时候没注意。可以使用xpath中//尝试抓取。竟然成功了。。。。与之前相比就是多了一个/
# 之前的 school = "".join(lis[0].xpath("./tr[%s]/td[3]/text()"%i)) # 现在的 school = "".join(lis[0].xpath("./tr[%s]/td[3]//text()"%i))
2020.07.20 记录几个写断点自动恢复的心得
22 注意每次用click之后要延时一会儿,可以用等待元素出现(隐式等待),或者直接暴力等待。
from lxml import etree from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.action_chains import ActionChains webDriverWait(driver, 10).until(EC.new_window_is_opened(driver.window_handles))
23 我用的断点自动恢复的方法是将序号信息写入一个临时文件,命名为record,每次循环开始之前就从这个文件取序号数据(字符串格式)。循环用while来写,注意一般将循环加1操作放在循环最后,如果有特殊需要经过慎重考虑可以放在第一位,注意while的结束条件
24 如果是多重嵌套循环,一定注意,在内层循环结束之后,一定在外层将数据重新置零。不然错误不好找。(因为断点重传的变量在本方法内是全局变量)
25 不知道之前写没写,linux服务器后台运行程序
cd /home/mysoft/spyder/major_sun/ nohup python3 /home/mysoft/spyder/major_sun/sun_major_rank.py > ./run.log 2>&1 &
2020/07/24 23:00
26 今天写爬虫,重温自己的下一页框架,在此小结一个
可以通过检测有点击下一页按钮,检测最新的driver与之前的driver的url是否相同,如果相同则说明已经到达最后一页,返回空,如果不一样,则返回driver。
因此,此方法的首页必须单独处理
27 元素获取文本信息是ele.text属性,而不是ele.text()方法。
28 对于跨区域的元素的点击事件,如果确定其可以正常工作,则可以加try except
29 关闭多于窗口,可以先在最开始设置变量before_handle为当前窗口,后续打开再多窗口,只要这个窗口不关闭,其他都可以关闭。可以构建死循环,一直关闭最后一个窗口,直到窗口等于before_handle 。然后从0开始关闭,,,,具体使用自己定