利用python+selenium采集京东商品信息

  今天我们用 python+ selenuim 自动框架来爬取京东商品信息(不要问我为什么又是京东,因为京东不需要登录也可以对商品进行搜索),Selenium简而言之就是用来模仿人类操作,解放双手,提高生产力的,哈哈,下面对selenuim做了一些介绍。

Selenium简介

  Selenium 是一个Web应用程序测试工具,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。一般的爬虫的方法是用python脚本直接对目标网站进行访问,而且只对目标数据进行采集,访问速度很快,这样目标网站很容易就识别出你是机器人,然后把你封锁了。而使用selenium写爬虫,python脚本操控浏览器进行访问,也就是说python脚本和目标网站之间多了个浏览器的操作,这样的行为更像是人类行为,这样很多难爬的网站也可以轻而易举的抓数据了。

准备

首先,安装selenuim,方法同其他第三方库的安装方法一样,都是使用pip命令

pip install selenium


安装好了selenuim以后,还得为其安装一个可以驱动才能使他正常工作。因为我使用的是谷歌浏览器,所以下载了谷歌驱动,当然啦也有火狐驱动。下载与浏览器版本相对应的驱动(如果没有对应版本,下载一个版本靠近的也是可以的),下面是两个驱动的下载地址:

     - 谷歌驱动:(点击下载)
     - 火狐驱动:(点击下载)

利用python+selenium采集京东商品信息_第1张图片


  下载好了之后就是驱动的安装了,Firefox驱动与Chrome驱动的安装方法一样,只需将下载好的驱动放入你的python安装路径下的Script目录下就可以了(放在Script文件夹下就不需要配置环境变量)

利用python+selenium采集京东商品信息_第2张图片
到这里,selenuim的相关安装就完成了,下面就开始我们今天的任务了。

一,导入相关依赖

import time
import json
from pyquery import PyQuery as pq
#pyquery是个解析库
from selenium import webdriver
#导入驱动webdriver
from selenium.webdriver.common.by import By
#By是selenium中内置的一个class,在这个class中有各种方法来定位元素
from selenium.webdriver.support.ui import WebDriverWait
#设置浏览器驱动休眠等待,避免频繁操作封ip
from selenium.webdriver.support import expected_conditions as EC
#判断一个元素是否存在,是否加载完毕等一系列的场景判断方法

二,使用selenium EC对浏览器进行操作

  首先,用 Chrome 浏览器打开商品首页,我们很容易发现该网页是一个 动态加载 的网页,刚打开网页时只会显示 30 个商品的信息,只有向下拖动网页时,它才会加载剩下 30 个商品的信息。这里我们可以使用 selenium 模拟浏览器下拉网页,并通过EC判断网页元素是否加载完成,从而获取网站全部商品的信息。

def search():
    browser.get('https://www.jd.com/')
    try:
        input = wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#key"))
        )  # 等待搜索框加载出来
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#search > div > div.form > button"))
        )  # 等待搜索按钮可以被点击
        input[0].send_keys(keyword)  # 向搜索框内输入关键词
        submit.click()  # 点击搜索
        time.sleep(2)  # 加入时间间隔,速度太快可能会抓不到数据
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")  # 下拉到网页底部
        wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
        )  # 等待最后一个商品信息加载完毕
        html = browser.page_source
    except TimeoutError:
        search()

三,使用selenium EC实现翻页操作

  与第一页相似,也是通过EC判断网页元素是否加载完成,并加入延时,防止抓不到数据

def next_page(page_number):
    try:
        button = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.pn-next > em'))
        )  # 等待翻页按钮可以点击
        button.click()  # 点击翻页按钮
        wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(30)"))
        )  # 等到30个商品都加载出来
        time.sleep(2)
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)
        wait.until(# 等到60个商品都加载出来
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
        )
        html = browser.page_source
        find_save(html)  # 调用函数筛选数据
    except TimeoutError:
        return next_page(page_number)

四,提取数据并保存

  这里使用pyquery库对网页源码进行解析,使用CSS_SELECTOR选择元素,一定要找准参考元素的位置,例如,将鼠标放至搜索框,右击检查,则跳转到搜索框对应代码,在选中的代码上右击,点击Copy > Copy selector,就得到了我们需要的 #key 了,之后通过.text()得到内容,最后将python对象转化为json数据并写入json文件。

def find_save(html):
    doc = pq(html)
    items = doc('#J_goodsList > ul > li').items()
    for item in items:
        product = {
            'name': item('.p-name a').text(),
            'price': item('.p-price i').text(),
            'commit': item('.p-commit a').text()
        }
        data_list.append(product)  # 写入全局变量
        # 把全局变量转化为json数据
        content = json.dumps(data_list, ensure_ascii=False, indent=2)
        with open("E:\python\project\selenium\info.json", "w", encoding="utf-8") as f:
            f.write(content)
    print("json文件写入成功")

五,编写调用主函数

  通过使用for循环来控制爬取的页数,并加入延迟

def main():
    print("第", 1, "页:")
    search()
    for i in range(2, 6):  # 爬取2-5页
        time.sleep(2)  # 设置延迟
        print("第", i, "页:")
        next_page(i)


if __name__ == "__main__":
    main()

补充

  为了提高爬虫效率,可以将浏览器设置为无图模式,即不加载图片,这样可以提高采集速度

options = webdriver.ChromeOptions()
options.add_experimental_option('prefs'{'profile.managed_default_content_settings.images': 2}) 
browser = webdriver.Chrome(options=options)

看一下结果:
利用python+selenium采集京东商品信息_第3张图片


附完整代码:

import time
import json
from pyquery import PyQuery as pq
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

# 不加载图片
options = webdriver.ChromeOptions()
options.add_experimental_option('prefs', {'profile.managed_default_content_settings.images': 2})
browser = webdriver.Chrome(options=options)
wait = WebDriverWait(browser, 20)  # 设置等待时间
data_list = []  # 设置全局变量用来存储数据
keyword = "平凡的世界"  # 商品名称


def search():
    browser.get('https://www.jd.com/')
    try:
        input = wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#key"))
        )  # 等待搜索框加载出来
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#search > div > div.form > button"))
        )  # 等待搜索按钮可以被点击
        input[0].send_keys(keyword)  # 向搜索框内输入关键词
        submit.click()  # 点击搜索
        time.sleep(2)  # 加入时间间隔,速度太快可能会抓不到数据
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")  # 滑动到底部
        wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
        )  # 等待最后一个商品信息加载完毕
        html = browser.page_source
        find_save(html)  # 调用函数筛选数据
    except TimeoutError:
        search()


def next_page(page_number):
    try:
        button = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.pn-next > em'))
        )  # 等待翻页按钮可以点击
        button.click()  # 点击翻页按钮
        wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(30)"))
        )  # 等到30个商品都加载出来
        time.sleep(2)
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)
        wait.until(# 等到60个商品都加载出来
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#J_goodsList > ul > li:nth-child(60)"))
        )
        html = browser.page_source
        find_save(html)  # 调用函数筛选数据
    except TimeoutError:
        return next_page(page_number)



def find_save(html):
    doc = pq(html)
    items = doc('#J_goodsList > ul > li').items()
    # print(items)
    for item in items:
        product = {
            'name': item('.p-name a').text(),
            'price': item('.p-price i').text(),
            'commit': item('.p-commit a').text()
        }
        data_list.append(product)  # 写入全局变量
        # 把全局变量转化为json数据
        content = json.dumps(data_list, ensure_ascii=False, indent=2)
        with open("E:\python\project\selenium\info.json", "w", encoding="utf-8") as f:
            f.write(content)
    print("json文件写入成功")


def main():
    print("第", 1, "页:")
    search()
    for i in range(2, 6):  # 爬取2-5页
        time.sleep(2)  # 设置延迟
        print("第", i, "页:")
        next_page(i)


if __name__ == "__main__":
    main()

如有错误,欢迎私信纠正,谢谢支持!

你可能感兴趣的:(python,网络爬虫,python,selenium,css)