接着上一回。
这段程序实现从淘宝主页开始,输入搜索信息(搜索‘手表’),确定搜索后,爬取结果前20页所有的价格信息和地区信息(其他信息也可以获取,暂时只获取了这两个),最后用matplotlib绘制了手表价格与数量的频率图。
可以看出来,普通手表价格集中在50-400元左右。
下面介绍程序思路:
思路还是利用selenium模块打开网页,返回页面源码,然后利用bs4解析源码,获取信息。
这次尝试在selenium库上载了大跟头,主要遇到了以下几个问题
1.跳转页面次数不对
一开始利用selenium定位淘宝“下一页”按钮,获取这这一页信息后直接跳转下一页。结果发现,翻页的次数总是少于预期的次数。后来经过多次尝试,发现问题应该是跳转页面后元素没有加载完成,以致无法翻页。虽然设置了显示等待,但还是没有奏效,后来设置了3s的强制等待后,翻页次数终于达到了预期。
2.跳转页面后源码未变
好不容易解决了跳转次数不对的问题,后来发现不管翻了多少页,打印出来的信息都是相同的,都是第一页信息。也就是说,浏览器虽然翻页过去了,程序获得的源码却未变。也是搜索了很多信息但是一直未解决。有说是因为句柄未改(但是我根本不知道句柄是啥),而且按照所写的方法去试了试,还是没有改变。后来检索到可能还是页面还未加载完成,于是,我又强制等待了3s,终于ok。
代码:
import time
import re
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
url = 'https://www.taobao.com' # 淘宝首页
max_page_account = 20 # 最大页面数
search_contents = '手表' # 搜索内容
# 打开页面
browser = webdriver.Chrome()
browser.get(url)
wait = WebDriverWait(browser, 10)
# 价格列表 和 地区列表
price_list = []
location_list = []
def init():
# 等待搜索框 与 搜索按钮 加载完成
input_contents = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#q'))
)
bnt_search = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))
)
# 输入 搜索内容,点击 搜索按钮
input_contents.send_keys(search_contents)
bnt_search.click()
def next_page():
"""翻页"""
# 定位 “下一页” 按钮
bnt_next_page = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.next > a'))
)
bnt_next_page.click()
time.sleep(5) # 强制等待5s,否则页面的源码不会改变
def get_info():
"""获取信息"""
# 等待 商品列表 加载完成
wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist > div > div'))
)
page = browser.page_source # 获取源码
soup = BeautifulSoup(page, 'html.parser') # 用beautifulsoup解析源码
items = soup.find('div', class_='grid g-clearfix') # 获取商品列表信息
itemlist = items.find_all('div', class_=re.compile(r'^item J_MouserOnverReq'))
for item in itemlist:
price = item.find('div', class_='price g_price g_price-highlight').find('strong').get_text()
location = item.find('div', class_='location').get_text()
price_list.append(float(price))
location_list.append(location)
def plot_image(item_list, x_label, y_label):
"""调用获取信息函数并绘图"""
count = 0
while count < max_page_account: # 遍历要求的页数
count += 1
get_info()
time.sleep(5) # 等待5s后再翻页
if count != max_page_account:
next_page()
# 绘制频率图
plt.hist(item_list, 50, rwidth=0.8) # 这一段注释在博客里单独解释
tick = np.linspace(0, 5000, 20)
plt.xticks(tick)
plt.tick_params(labelsize=6)
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.title(x_label + "-" + y_label)
plt.show()
init()
x_label = "price"
y_label = "amount"
plot_image(price_list, x_label, y_label)
主要解释一下绘图部分代码。
在 “#绘制频率图”下:
第一行是hist图,第一个参数是x轴数据列表,这里即使价格列表;第二个参数是分隔数量,比如手表价格是200-2000,如果分隔数量是10,那么每隔区间就是(2000-200)/10,通俗来说就是柱状图的数量。第三个参数是柱状图的宽度
第2~4行是设置x轴刻度,如果不设置也行,hist图会默认,但是我觉得刻度不够精确,重新设置一下。第2行是定义刻度对象,第一个参数是刻度最小值,第二个参数是最大值,第三个参数是间隔数量。第4行是设置x轴刻度字体大小
5~7行是设置x,y轴标签以及图题,貌似matplotlib不支持中文,还未解决。
最后显示图,未保存。
下一次应该会学习一下如何从网页上下载图片。