今天我们用 python+ selenuim 自动框架来爬取京东商品信息(不要问我为什么又是京东,因为京东不需要登录也可以对商品进行搜索),Selenium简而言之就是用来模仿人类操作,解放双手,提高生产力的,哈哈,下面对selenuim做了一些介绍。
Selenium 是一个Web应用程序测试工具,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。一般的爬虫的方法是用python脚本直接对目标网站进行访问,而且只对目标数据进行采集,访问速度很快,这样目标网站很容易就识别出你是机器人,然后把你封锁了。而使用selenium写爬虫,python脚本操控浏览器进行访问,也就是说python脚本和目标网站之间多了个浏览器的操作,这样的行为更像是人类行为,这样很多难爬的网站也可以轻而易举的抓数据了。
首先,安装selenuim,方法同其他第三方库的安装方法一样,都是使用pip命令
pip install selenium
安装好了selenuim以后,还得为其安装一个可以驱动才能使他正常工作。因为我使用的是谷歌浏览器,所以下载了谷歌驱动,当然啦也有火狐驱动。下载与浏览器版本相对应的驱动(如果没有对应版本,下载一个版本靠近的也是可以的),下面是两个驱动的下载地址:
- 谷歌驱动:(点击下载)
- 火狐驱动:(点击下载)
下载好了之后就是驱动的安装了,Firefox驱动与Chrome驱动的安装方法一样,只需将下载好的驱动放入你的python安装路径下的Script
目录下就可以了(放在Script文件夹下就不需要配置环境变量)
到这里,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
#判断一个元素是否存在,是否加载完毕等一系列的场景判断方法
首先,用 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()
与第一页相似,也是通过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)
附完整代码:
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()
如有错误,欢迎私信纠正,谢谢支持!