python爬虫之selenium、phantomJs
图片懒加载技术
什么是图片懒加载技术
图片懒加载是一种网页优化技术。图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间。为了解决这种问题,通过前后端配合,使图片仅在浏览器当前视窗内出现时才加载该图片,达到减少首屏图片请求数的技术就被称为“图片懒加载”。
如何实现图片懒加载技术
在网页源码中,在img标签中首先会使用一个“伪属性”(通常使用src2,original......)去存放真正的图片链接而并非是直接存放在src属性中。当图片出现到页面的可视化区域中,会动态将伪属性替换成src属性,完成图片的加载。
如何破解图片懒加载技术
其实很简单,在对标签属性进行定位的时候,仔细观察它真正的属性进行提取。
例如:
import requests
from lxml import etree def main():
responses = requests.get(url=url, headers=headers)
coding = responses.apparent_encoding
responses.encoding = coding
res_text = responses.text
# 创建etree对象
tree = etree.HTML(res_text)
div_lst = tree.xpath('//div[@id="container"]/div')
for one_div in div_lst:
image_name = one_div.xpath('.//img/@alt')[0]
image_url = one_div.xpath('.//img/@src2')
print(image_name)
print(image_url) if __name__ == '__main__':
headers = {"User-Agent":'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'}
url = 'http://sc.chinaz.com/tupian/gudianmeinvtupian.html'
main()
以上例子中就将src属性换为了src2属性。
selenium
1 什么是Selenium?
selenium是Python的一个第三方库,对外提供的接口可以操作浏览器,然后让浏览器完成自动化的操作。 
selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器。
2 前期准备
selenium安装就不再概述了
查看自己的谷歌浏览器版本

查看自己对用的谷歌驱动: https://blog.csdn.net/huilan_same/article/details/51896672
下载自己的谷歌驱动: http://chromedriver.storage.googleapis.com/index.html
这里我下载是:

然后加压后把它放到python解释器的scripts目录中即可.
3 简单示例
from selenium import webdriver
from time import sleep # 启动你的谷歌浏览
driver = webdriver.Chrome()
# 用get方法打开百度首页
driver.get('https://www.baidu.com')
# 找到第一个链接标签的文本并点击
driver.find_elements_by_link_text('设置')[0].click()
# 睡一秒
sleep(1)
# 找到搜索设置并点击
driver.find_elements_by_link_text('搜索设置')[0].click()
sleep(2)
# 找到id为nr的标签
ch = driver.find_element_by_id('nr')
sleep(1)
# 选择第3个标签点击
# ch.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
ch.find_element_by_xpath('.//option[3]').click()
sleep(2)
# 保存设置
driver.find_elements_by_class_name("prefpanelgo")[0].click()
sleep(2)
# 处理弹出的警告
driver.switch_to_alert().accept()
sleep(2)
# 网搜索框里传入数据
driver.find_element_by_id('kw').send_keys('nba')
sleep(2)
# 点击搜索按钮
driver.find_element_by_id('su').click()
sleep(2)
# 关闭驱动
driver.close()
# 关闭浏览器
driver.quit()
这是一个设置百度搜索每个页面显示50条数据并搜索nba的程序
Selenium支持的浏览器非常多,如Chrome、Firefox、Edge等,还有Android、BlackBerry等手机端的浏览器。另外,也支持无界面浏览器PhantomJS,也就是后面要说的内容。
4 webdriver的元素定位
# 通过id属性
find_element_by_id()
# 通过name属性
find_element_by_name()
# 通过class的名字
find_element_by_class_name()
# 通过标签的名字
find_element_by_tag_name()
# 通过链接标签的文本
find_element_by_link_text()
# 通过链接标签的部分文本
find_element_by_partial_link_text()
# 通过xpath
find_element_by_xpath()
# 通过css选择器
find_element_by_css_selector()
注意:
1 find_element_by_xxx找的是第一个符合条件的标签,find_elements_by_xxx找的是所有符合条件的标签。
2 elenium还提供了通用方法find_element(),它需要传入两个参数:查找方式By和值。实际上,它就是find_element_by_id()
这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id),二者得到的结果完全一致。
5 对节点进行交互
# 通过id知道输入框
input = browser.find_element_by_id('q')
# 向里面出入文本MAC
input.send_keys('MAC')
# 清楚文本框
input.clear()
# 再传入一个文本IPhone
input.send_keys('IPhone')
# 通过classname找到一个事件
button = browser.find_element_by_class_name('btn-search')
# 点击它
button.click()
6 动作链
什么是动作链呢?
在节点交互中,交互动作都是针对某个节点执行的。比如对于输入框,就调用它输入和清空的方法,对于按钮,就调用它点击的方法,其实还有一些操作,它们没有特定的执行对象,比如鼠标拖拽,键盘按键,它们使用另一种方式来执行,就是动作链。
以下例子演示了把一个节点从一处拖动到另一处:
from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains driver = webdriver.Chrome()
# 菜鸟教程的js演示代码
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
driver.get(url)
# 进入嵌套的页面
driver.switch_to.frame('iframeResult')
# 点位要拖动的标签
start = driver.find_element_by_css_selector('.ui-draggable')
# 拖动的目标标签
end = driver.find_element_by_css_selector('.ui-droppable')
# 创建一个鼠标事件
actions = ActionChains(driver)
# 点击要拖动的标签不松动
sleep(1)
actions.click_and_hold(start).perform()
# 然后移动到另一个标签
actions.move_to_element(end).perform()
# 往x轴移动40,y轴移动20
sleep(1)
actions.move_by_offset(xoffset=40, yoffset=20).perform()
# 释放动作
actions.release()
可能有人会对driver.switch_to.frame('iframeResult')这句代码有疑问


这个就是frame嵌套的。
在 web 应用中经常会出现 iframe 嵌套的应用,假设页面上有 A、B 两个 iframe,其中 B 在 A 内,那么定位 B 中的内容则需要先到 A,然后再到 B。
所以我们使用driver.switch_to.frame('iframeResult')直接进入嵌套的页面。
7 执行js
有些api是selenium没有提供的,比如下拉进度条,但是可以通过吗模拟运行js来实现。
from selenium import webdriver
from time import sleep driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 移动到页面最底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
sleep(2)
# 执行alert123这个代码 就是弹出123
driver.execute_script("alert('123')")
这一块自动化测试用的挺多的,想学自动化测试的同学可以多学习下。
8 获取节点信息
通过page_source属性可以获取网页的源代码,接着就可以使用解析库(如正则表达式、Beautiful Soup、pyquery等)来提取信息了。
selenium自己也提供了提取节点信息的方法,如属性、文本等。这样的话,我们就可以不用通过解析源代码来提取信息了,非常方便。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as E
from selenium.webdriver.support.wait import WebDriverWait driver = webdriver.Chrome()
# 访问亚马逊首页
driver.get("https://www.amazon.cn/")
# 显示等待10秒
wait = WebDriverWait(driver, 10)
# 判断元素是否被加载到了dom中
wait.until(E.presence_of_element_located((By.ID,'cc-lm-tcgShowImgContainer')))
# 通过选择器找到这个元素
tag=driver.find_element(By.CSS_SELECTOR,'#cc-lm-tcgShowImgContainer img')
#获取标签属性,
print(tag.get_attribute('src'))
#获取标签ID,位置,名称,大小(了解)
print(tag.id)
print(tag.location)
print(tag.tag_name)
print(tag.size)
driver.close()
9 延时等待
在selenium中,get()方法会在页面框加载结束后,结束执行。此时如果获得get_source,可能不是浏览器完全加载完成后的页面,某些额外的js,ajax可能不一定获取到,所以需要延时等待一下,确保节点加载出来了,这里等待的方式有2中:显式等待和隐式等待。
1 显式等待
上个例子就用到了显式等待,显式等待会设置一个固定的等待时间,但是实际情况是由于外界因素的影响,我们也不可能判断出需要多少时间,所有显示等待还有一种写法,如果在规定时间加载出了这个节点,就对这个节点进行操作,如果没有加载出,就抛出超时异常。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as E
from selenium.webdriver.support.wait import WebDriverWait driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
input_tag = driver.find_element_by_id('kw')
input_tag.send_keys('美女')
# 模拟键盘回车键
input_tag.send_keys(Keys.ENTER)
# 创建一个显式等待
wait = WebDriverWait(driver, 10)
# 等待直到加载出content_left(content是左半区)
wait.until(E.presence_of_element_located((By.ID, 'content_left')))
content = driver.find_element(By.CSS_SELECTOR, "#content_left")
print(content)
driver.close()
如果将webDriverWait中的时间设置过低,会报错:

2 隐式等待
当使用隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome()
# 设置隐式等待
driver.implicitly_wait(10)
driver.get('https://www.baidu.com/')
input_tag = driver.find_element_by_id('kw')
input_tag.send_keys('NBA')
# 模拟键盘回车键
input_tag.send_keys(Keys.ENTER)
content = driver.find_element(By.CSS_SELECTOR, "#content_left")
print(content)
driver.close()
10 cookie
使用selenium还可以对cookie进行操作,获取,添加,删除cookie:
from selenium import webdriver driver = webdriver.Chrome()
driver.get('https://www.zhihu.com/explore')
# 获取cookie
print(driver.get_cookies())
# 添加cookie
driver.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
print(driver.get_cookies())
# 删除cookie
driver.delete_all_cookies()
print(driver.get_cookies())
[{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'l_n_c', 'path': '/', 'secure': False, 'value': ''}, {'domain': 'www.zhihu.com', 'expiry': 1555763561.220174, 'httpOnly': False, 'name': 'tgw_l7_route', 'path': '/', 'secure': False, 'value': '537a925d07d06cecbf34cd06a153f671'}, {'domain': '.zhihu.com', 'expiry': 1650370661.220268, 'httpOnly': False, 'name': 'q_c1', 'path': '/', 'secure': False, 'value': '9ca2467feeaa4987a63360951034c876|1555762662000|1555762662000'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '270095e8c0bc05224a3eb61674d59ce0'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220341, 'httpOnly': False, 'name': 'r_cap_id', 'path': '/', 'secure': False, 'value': '"ZjhkMmMxZWE5NjlhNDY3OWE4ODA1NjI4MjhkYzc0Y2Y=|1555762662|257a989723432c66a22d10794cd998b22d419794"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220391, 'httpOnly': False, 'name': 'cap_id', 'path': '/', 'secure': False, 'value': '"NTY2OWZiYmI2ODdlNDFkZWE1MzBiZTEyYTQ5MDFmYzk=|1555762662|5c5e5d6a7150c0da99f86af9d85cc63cafbea752"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220438, 'httpOnly': False, 'name': 'l_cap_id', 'path': '/', 'secure': False, 'value': '"Njk2NWI1ZTIxYjg2NGZhZDhiOGJiYjM5ODg0Y2U2ZmM=|1555762662|6a4e7d4ab33c72012e5bf133ffadfe34aa88b8eb"'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'n_c', 'path': '/', 'secure': False, 'value': ''}, {'domain': '.zhihu.com', 'expiry': 1650370664.061236, 'httpOnly': False, 'name': 'd_c0', 'path': '/', 'secure': False, 'value': '"AJDm50C_Tg-PTkHkupcfIBQqf8xnPhGsu4M=|1555762665"'}, {'domain': '.zhihu.com', 'expiry': 1633522664.358119, 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': 'mzatpYVVTALiHdu45yqz9q4yljxCPZ7n'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': 'ec95407d-3b81-4e43-81d5-277adf4b33b9'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utma', 'path': '/', 'secure': False, 'value': '51854390.2113439272.1555762665.1555762665.1555762665.1'}, {'domain': '.zhihu.com', 'expiry': 1555764464, 'httpOnly': False, 'name': '__utmb', 'path': '/', 'secure': False, 'value': '51854390.0.10.1555762665'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': '__utmc', 'path': '/', 'secure': False, 'value': ''}, {'domain': '.zhihu.com', 'expiry': 1571530664, 'httpOnly': False, 'name': '__utmz', 'path': '/', 'secure': False, 'value': '51854390.1555762665.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utmv', 'path': '/', 'secure': False, 'value': '51854390.000--|3=entry_date=20190420=1'}]
[{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'l_n_c', 'path': '/', 'secure': False, 'value': ''}, {'domain': 'www.zhihu.com', 'expiry': 1555763561.220174, 'httpOnly': False, 'name': 'tgw_l7_route', 'path': '/', 'secure': False, 'value': '537a925d07d06cecbf34cd06a153f671'}, {'domain': '.zhihu.com', 'expiry': 1650370661.220268, 'httpOnly': False, 'name': 'q_c1', 'path': '/', 'secure': False, 'value': '9ca2467feeaa4987a63360951034c876|1555762662000|1555762662000'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '270095e8c0bc05224a3eb61674d59ce0'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220341, 'httpOnly': False, 'name': 'r_cap_id', 'path': '/', 'secure': False, 'value': '"ZjhkMmMxZWE5NjlhNDY3OWE4ODA1NjI4MjhkYzc0Y2Y=|1555762662|257a989723432c66a22d10794cd998b22d419794"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220391, 'httpOnly': False, 'name': 'cap_id', 'path': '/', 'secure': False, 'value': '"NTY2OWZiYmI2ODdlNDFkZWE1MzBiZTEyYTQ5MDFmYzk=|1555762662|5c5e5d6a7150c0da99f86af9d85cc63cafbea752"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220438, 'httpOnly': False, 'name': 'l_cap_id', 'path': '/', 'secure': False, 'value': '"Njk2NWI1ZTIxYjg2NGZhZDhiOGJiYjM5ODg0Y2U2ZmM=|1555762662|6a4e7d4ab33c72012e5bf133ffadfe34aa88b8eb"'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'n_c', 'path': '/', 'secure': False, 'value': ''}, {'domain': '.zhihu.com', 'expiry': 1650370664.061236, 'httpOnly': False, 'name': 'd_c0', 'path': '/', 'secure': False, 'value': '"AJDm50C_Tg-PTkHkupcfIBQqf8xnPhGsu4M=|1555762665"'}, {'domain': '.zhihu.com', 'expiry': 1633522664.358119, 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': 'mzatpYVVTALiHdu45yqz9q4yljxCPZ7n'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': 'ec95407d-3b81-4e43-81d5-277adf4b33b9'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utma', 'path': '/', 'secure': False, 'value': '51854390.2113439272.1555762665.1555762665.1555762665.1'}, {'domain': '.zhihu.com', 'expiry': 1555764464, 'httpOnly': False, 'name': '__utmb', 'path': '/', 'secure': False, 'value': '51854390.0.10.1555762665'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': '__utmc', 'path': '/', 'secure': False, 'value': ''}, {'domain': '.zhihu.com', 'expiry': 1571530664, 'httpOnly': False, 'name': '__utmz', 'path': '/', 'secure': False, 'value': '51854390.1555762665.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utmv', 'path': '/', 'secure': False, 'value': '51854390.000--|3=entry_date=20190420=1'}, {'domain': 'www.zhihu.com', 'expiry': 2186482664, 'httpOnly': False, 'name': 'name', 'path': '/', 'secure': True, 'value': 'germey'}]
[]
11 异常处理
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchFrameException try:
driver = webdriver.Chrome()
driver.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
driver.switch_to.frame('iframssseResult')
except TimeoutException as e:
print(e)
except NoSuchFrameException as e:
print(e)
finally:
driver.close()
超时等待哪里就可以这样写。
phantomJs
phantomJs是一款无界面的浏览器,其自动化操作流程和上面的谷歌浏览器是一致的。
由于是无界面的,为了能够展示自动化操作流程,PhantomJS为用户提供了一个截屏的功能,使用save_screenshot函数实现。
from selenium import webdriver
import time # exe路径
path = r'C:\phantomjs-2.1.1-windows\bin\phantomjs.exe'
driver = webdriver.PhantomJS(path)
driver.get("https://www.baidu.com")
time.sleep(2)
driver.save_screenshot(r'baidu.png')
my_input = driver.find_element_by_id('kw')
my_input.send_keys('nba')
driver.save_screenshot(r'nba.png')
# 查找搜索按钮
button = driver.find_elements_by_class_name('s_btn')[0].click()
time.sleep(3)
driver.save_screenshot(r'show.png')
driver.close()
driver.quit()
使用selenum+phantomJs可以解决某些网页js动态加载问题。
selenium+phantomJs爬取豆瓣电影的电影信息
首先来看下这个页面:https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action=

查看他的网页源代码:发现它是js动态加载显示的
from selenium import webdriver
import time def main():
path = r'C:\phantomjs-2.1.1-windows\bin\phantomjs.exe'
driver = webdriver.PhantomJS(path)
driver.get(url)
time.sleep(2)
driver.save_screenshot(r'1.png')
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
time.sleep(2)
driver.save_screenshot('2.png')
time.sleep(1)
html_source = driver.page_source
with open('source.html', 'w', encoding='utf-8') as f:
f.write(html_source)
driver.quit() if __name__ == "__main__":
url = 'https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action='
main()
这样就可以拿到它的源码了:

谷歌无头浏览器 Headless Chrome
由于phantomJs已经停止了更新和维护,所以推荐使用谷歌的无头浏览器,这是一款无界面的谷歌浏览器
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep # 创建一个无头浏览器对象
chrome_options = Options()
# 设置它为无框模式
chrome_options.add_argument('--headless')
# 如果在windows上运行需要加代码
chrome_options.add_argument('--disable-gpu') browser = webdriver.Chrome(chrome_options=chrome_options)
browser.get('https://www.baidu.com/')
sleep(2)
browser.save_screenshot('first_page.png')
browser.quit()
使用谷歌无头浏览器爬取网易新闻的国内模块
单独写了一篇博客:https://www.cnblogs.com/xiaozx/p/10744604.html
python爬虫之selenium、phantomJs的更多相关文章
- Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
		
1,引言 在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor.本文记录了确定gsExtractor的技术路线过程中所做的编程实验.这是第二部分,第一 ...
 - [Python爬虫] :Selenium +phantomjs 利用 pyquery抓取脚本链接对应的内容
		
抓取上面对应链接的网页的文章的内容 ele = element.attr("onclick") self.driver.execute_script(ele) sub_seleni ...
 - [Python爬虫]使用Selenium操作浏览器订购火车票
		
这个专题主要说的是Python在爬虫方面的应用,包括爬取和处理部分 [Python爬虫]使用Python爬取动态网页-腾讯动漫(Selenium) [Python爬虫]使用Python爬取静态网页-斗 ...
 - Python爬虫教程-26-Selenium + PhantomJS
		
Python爬虫教程-26-Selenium + PhantomJS 动态前端页面 : JavaScript: JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持 ...
 - Python爬虫之selenium库使用详解
		
Python爬虫之selenium库使用详解 本章内容如下: 什么是Selenium selenium基本使用 声明浏览器对象 访问页面 查找元素 多个元素查找 元素交互操作 交互动作 执行JavaS ...
 - Python 爬虫利器 Selenium 介绍
		
Python 爬虫利器 Selenium 介绍 转 https://mp.weixin.qq.com/s/YJGjZkUejEos_yJ1ukp5kw 前面几节,我们学习了用 requests 构造页 ...
 - Python爬虫之selenium的使用(八)
		
Python爬虫之selenium的使用 一.简介 二.安装 三.使用 一.简介 Selenium 是自动化测试工具.它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏 ...
 - Python爬虫之selenium高级功能
		
Python爬虫之selenium高级功能 原文地址 表单操作 元素拖拽 页面切换 弹窗处理 表单操作 表单里面会有文本框.密码框.下拉框.登陆框等. 这些涉及与页面的交互,比如输入.删除.点击等. ...
 - python爬虫利器Selenium使用详解
		
简介: 用pyhon爬取动态页面时普通的urllib2无法实现,例如下面的京东首页,随着滚动条的下拉会加载新的内容,而urllib2就无法抓取这些内容,此时就需要今天的主角selenium. Sele ...
 
随机推荐
- How to set spring boot  active profiles with maven profiles
			
In the previous post you could read about separate Spring Boot builds for a local development machin ...
 - 12.app后端如何选择合适的数据库产品
			
app后端的开发中,经常要面临的一个问题是:数据放在哪里? mysql ?redis?mongodb? 现在有这么多优秀的开源数据库产品,怎么根据业务场景来选择合适的数据? 常用的数据库产品的优缺点又 ...
 - Cookie防篡改机制
			
一.为什么Cookie需要防篡改 为什么要做Cookie防篡改,一个重要原因是 Cookie中存储有判断当前登陆用户会话信息(Session)的会话票据-SessionID和一些用户信息. 当发起一个 ...
 - BZOJ_1098_[POI2007]办公楼biu_链表优化BFS
			
BZOJ_1098_[POI2007]办公楼biu_链表优化BFS Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的 电话号 ...
 - 重构:以Java POI 导出EXCEL为例2
			
前言 上一篇博文已经将一些对象抽象成成员变量以及将一些代码块提炼成函数.这一节将会继续重构原有的代码,将一些函数抽象成类,增加成员变量,将传入的参数合成类等等. 上一篇博文地址:http://www. ...
 - Robot Framework源码解析(2) - 执行测试的入口点
			
我们再来看 src/robot/run.py 的工作原理.摘录部分代码: from robot.conf import RobotSettings from robot.model import Mo ...
 - 【Python3爬虫】你会怎么评价复仇者联盟4?
			
一.写在前面 最近复仇者联盟4正在热映中,很多人都去电影院观看了电影,那么对于这部电影,看过的人都是怎么评价的呢?这时候爬虫就可以派上用场了! 二.主要思路 首先打开豆瓣电影,然后进入复仇者联盟4的详 ...
 - 再遇angular(angular4项目实战指南)
			
这两天看了看angular4的文档,发现他和angular1.X的差别真的是太大了,官方给出的那个管理英雄的Demo是一个非常好的入门项目,这里给出一个管理个人计划的小项目,从头至尾一步一步讲解如何去 ...
 - Java8新特性之四:接口默认方法和静态方法
			
在JDK1.8以前,接口(interface)没有提供任何具体的实现,在<JAVA编程思想>中是这样描述的:"interface这个关键字产生了一个完全抽象的类,它根本就没有提供 ...
 - WebWorker 中将已处理好的 VDOM 数据提交主线程渲染 DOM
			
上篇文章讲了 WebWorker 的简单用法,其实网上很多类似的文章,我写的也比较垃圾.不会的建议可以网上看比较好点的资料. 这里我会先讲下我的大致思路.然后会贴上一堆不实用的垃圾代码供参考. Web ...