用Beyond Compare分析网页是否含有动态部分。
找到你锁需的内容,用常规方式爬取测验,如果不能爬取,则应该考虑是否有动态网页了!!
我之前已经掌握一种方案,找到动态网页的js文件,而且还非常简单,但是美中不足的是要找到加载出来的js文件,并找到这些动态页面的规律,这里需要靠人为查找。
推荐教程:Python爬取js动态页面
安装:
selenium 的安装很简单:
pip install selenium
phantomjs的安装有点复杂:
先下载安装nodejs,很简单。
如果需要用浏览器显示还要安装对应的浏览器driver:
查看chromedriver教程
selenium + chrome/phantomjs教程
直接代码,代码中有详细解释,没解释到的后文会给出解释:
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from pyquery import PyQuery as pq
import pymongo
client = pymongo.MongoClient('localhost')
db = client['tbmeishi']
driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true','--load-images=false','--disk-cache=true'])
driver.set_window_size(1280,2400) #当无浏览器界面时必须设置窗口大小
#driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
def search():
try:
driver.get('https://www.taobao.com/') #加载淘宝首页
#等待页面加载出输入框
input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#q")))
#等待页面出现搜索按钮
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button")))
input.send_keys('美食') #向输入框中输入‘美食’关键字
submit.click() #点击搜索按钮
#等待页面加载完
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.total')))
#第一页加载完后,获取第一页信息
get_products()
return total.text
except TimeoutException:
return search()
def next_page(page_number):
try:
# 等待页面出现搜索按钮
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > ul > li.item.next > a")))
submit.click() # 点击确定按钮
#判断当前页面是否为输入页面
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number)))
#第i页加载完后,获取页面信息
get_products()
except TimeoutException:
return next_page(page_number)
def get_products():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = driver.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
print(product)
#save_to_mongo(product)
def save_to_mongo(result):
try:
if db['product'].insert(result):
print('存储到MONGODB成功', result)
except Exception:
print('存储到MONGODB失败', result)
def main():
try:
total = search()
total = int(re.compile('(\d+)').search(total).group(1))
for i in range(2,total+1):
print('第 %d 页'%i)
next_page(i)
except Exception as e:
print('error!!!',e)
finally:
driver.close()
if __name__ == '__main__':
main()
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
当用无界面操作时,必须注意设置窗口大小,并且尽量设置大一点,如果这个尺寸设置得比较小,我们就不得用JavaScript的scroll命令来模拟页面往下滑动的效果以显示更多内容,所以设置一个比较大的窗口来渲染
driver.set_window_size(1280,2400)
selenium实现了一些类似xpath的功能,可以用driver直接获取我们想要的元素,直接调用下列方法:
但这种方法速度太慢,我们一般不采用,而是将driver直接获取网页源码:html = driver.page_source ,然后用lxml + xpath或BeautifulSoup对其解析;
除此之外还可以用另一种方法解析:pyquery
参考这两篇博文:
http://cuiqingcai.com/2636.html
http://blog.csdn.net/cnmilan/article/details/8727308
下面这段代码就是用pyquery方法解析的,真的很简单。
def get_products():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = driver.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
print(product)
selenium还包括很多方法:
注意:
在运行结束后一定要调用driver.close()或driver.quit()来退出phantomjs,不然phantomjs会一直占有内存资源。
建议用driver.service.process.send_signal(signal.SIGTERM)
可以强制kill,Windows下百度
Linux下:
ps aux | grep phantomjs #查看phantomjs进程
pgrep phantomjs | xargs kill #kill全部phantomjs
PhantomJS配置
driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true','--load-images=false','--disk-cache=true'])
--ignore-ssl-errors = [true|false] #是否检查CA证书、安全
--load-images = [true|false] #是否加载图片,一般不加载,节约时间
--disk-cache = [true|false] #是否缓存
最后,总结一下,常规爬取方法操作更简单,尤其是用selenium的一些方法的时候,初学者感到很困难;而且,用selenium+phantomjs方法会慢一些,应为这个相当于是一个人在访问网页,会需要等待加载时间,而常规爬取方法是直接拿网页代码,会快一些。当然,有点时候selenium+phantomjs会简单很多,它是假装一个人在访问,反爬虫也不易发现,而且有些网页有陷阱,传统方法会很麻烦,对于慢的问题,可以用多线程解决。
总而言之,case by case !!!!