准备工作:
库的安装:
:
pip3 install selenium
pip3 install pyquery
引入库与定义浏览器驱动对象
:
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from pyquery import PyQuery as pq
browser = webdriver.Chrome()
wait = WebDriverWait(browser,10)
在正式开始之前先解释一下接下来用到的几个常用表达:
1.显式等待
wait.until
,指定一个等待条件和最长等待时间,如果等待条件成立则立即返回,反之超过最长等待时间则抛出异常
2.
presence_of_element_located
:元素加载出,传入定位元组,如 (By.id,‘q’)
3.
text_to_be_present_in_element
:某个元素包含某文字
4.
element_to_be_clickable
:元素可点击
步骤流程
1.打开京东网站并模拟浏览器实现搜索功能
2.实现翻页功能
3.用CSS选择器爬取每一页商品的信息
1.模拟浏览器实现搜索功能
首先用browser打开京东官网并定位输入框的id
输入关键词
python
browser.get('https://www.jd.com/')
input = browser.find_element_by_id('key')
input.send_keys('python')
之前我们已经导入了类键盘库
from selenium.webdriver.common.keys import Keys
,可以使用
Keys.ENTER
回车按钮实现搜索功能
input.send_keys(Keys.ENTER)
同时我们还需要获取商品的总页数以实现接下来翻页次数的精确控制,打开搜索页面,定位最底部的
共xx页
中间的数字,复制选择器得到总页数
不要忘了设置处理异常,超时的话只要重新执行一次就可以了
def search():
try:
browser.get('https://www.jd.com/')
input = browser.find_element_by_id('key')
input.send_keys('python')
input.send_keys(Keys.ENTER)
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > em:nth-child(1) > b')))
return total.text
except TimeoutException:
return search()
实现翻页功能
在正常访问网站中,翻页方式有两种,一种是点击下一页按钮实现翻页,另一种则是在输入框中输入页数点击确定进行翻页,对于第一种翻页而言,如果中途出现了错误不方便处理,于是我们选择在输入框里输入页数并点击确定实现该功能,也就是要实现一种循环操作
定位找到输入页数的方框和确认按钮,复制选择器
input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > input')))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > a')))
input.clear() #去掉当前输入框显示的数字
input.send_keys(页码)
submit.click()
为了判断当前所在的页面是否为期望得到的页面,我们需要加一个判断条件:当前页码是否高亮
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#J_bottomPage > span.p-num > a.curr'),str(页码)))
最后仍然不要忘记处理超时异常
def next_page(页码数):
try:
input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > input')))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > a')))
input.clear()
input.send_keys(each_page)
submit.click()
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#J_bottomPage > span.p-num > a.curr'),str(each_page)))
except TimeoutException:
next_page(页码数)
爬取商品信息
分析网页结构可以看到每一个商品都是一个
class
为
gl-item
的标签,假如把每一个商品当做item的话,那么箭头所指的标签就是items,里面包含了该页面的所有商品,复制标签的选择器并用
wait.until
判断是否加载出来
接下来用pyquery得到源码
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_goodsList > ul')))
html = browser.page_source
doc = pq(html)
items = doc('#J_goodsList > ul > li').items() #调用items方法可以得到所有选择的内容
接下来对每一个
item
爬取它的标题,价格以及店铺
for item in items:
price = item.find('.p-price').text()
title = item.find('.p-name em').text().replace('\n','')
sales = item.find('.p-shopnum a').attr('title')
print(title,price,sales)
最后整理一下,得到总程序代码
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from pyquery import PyQuery as pq
browser = webdriver.Chrome()
wait = WebDriverWait(browser,10)
def search():
try:
browser.get('https://www.jd.com/')
input = browser.find_element_by_id('key')
input.send_keys('python')
input.send_keys(Keys.ENTER)
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > em:nth-child(1) > b')))
return total.text
get_products()
except TimeoutException:
return search()
def next_page(each_page):
try:
input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > input')))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_bottomPage > span.p-skip > a')))
input.clear()
input.send_keys(each_page)
submit.click()
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#J_bottomPage > span.p-num > a.curr'),str(each_page)))
get_products()
except TimeoutException:
next_page(each_page)
def get_products():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_goodsList > ul')))
html = browser.page_source
doc = pq(html)
items = doc('#J_goodsList > ul > li').items() #调用items方法可以得到所有选择的内容
for item in items:
price = item.find('.p-price').text()
title = item.find('.p-name em').text().replace('\n','')
sales = item.find('.p-shopnum a').attr('title')
print(title,price,sales)
def main():
total = search()
for i in range(2,int(total)+1):
next_page(i)
if __name__ == '__main__':
main()
最后放上一张效果图,因为我设置了10s等待的时间所以爬取比较慢,可以适当缩短时间