爬虫pycharm(python)的selenium+pyquery+CSS选择器模拟浏览器爬取京东商品信息

  • Post author:
  • Post category:python




准备工作:


库的安装:

:

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等待的时间所以爬取比较慢,可以适当缩短时间
在这里插入图片描述



版权声明:本文为weixin_45830664原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。