一、选题背景:
随着互联网的快速发展,电子商务平台已经成为人们日常生活的重要组成部分。淘宝作为中国最大的电商平台之一,拥有海量的商品信息和交易数据。近年来,由于新冠疫情的影响,人们对药品的需求量不断增加,尤其是感冒药。因此,通过对淘宝网各地感冒药销量的数据爬取和分析,可以了解感冒药的市场需求和销售情况,进一步探讨其背后的影响因素和消费行为特点,为药品生产、销售和监管等提供有益的参考。
此外,随着大数据和人工智能技术的不断发展,数据爬取和分析已经成为获取市场信息和了解消费者需求的重要手段之一。通过对淘宝网各地感冒药销量的数据爬取和分析,可以为相关企业和政府机构提供决策依据和参考,促进药品市场的健康发展,本选题旨在通过对淘宝网各地感冒药销量的数据爬取和分析,探讨感冒药市场需求和销售情况,为药品生产、销售和监管等提供有益的参考,促进药品市场的健康发展。
目标网站:https://s.taobao.com/
二、主题式网络爬虫设计方案:
内容:爬取淘宝页面上面的商品数据,商品的商品名,价格,销量,省份,店名等数据总共有100页,每一页有48个商品的信息需要获取。
主题式网络爬虫设计方案概述:
实现思路:主要就是用selenium打开网页,通过xpath或者类名或者id名定位到元素,然后获取完当页所需数据后,用click方法点击下一页,每次打开页面后进行一个判断看看是否有滑块,有的话就会调用自定义slider方法来对滑块进行处理,这样才能继续下一页数据的爬取。
技术难点:
在Python爬虫中,因为python爬虫程序会模拟用户来频繁的对淘宝的服务器发出请求,淘宝时不时的就会弹出滑块来验证用户的身份,这种滑块验证机制是一个常见的难点,类似的还有验证码和一些图像文字点击的验证机制,像这种机制通常用于防止自动化脚本的恶意访问和爬取。要解决这个问题,需要模拟用户真实的操作流程,例如移动滑块或点击某个按钮,而在本次数据爬取的过程中就是自定义slider方法来对滑块进行相应的移动滑块或点击处理,以此来达到对所有相关页面数据的获取。
反爬策略: 许多网站使用了反爬策略,如限制IP、限制访问频率等,这可能导致爬虫被禁止访问。需要解决这些问题,以保证爬虫的稳定运行。网页结构变化: 网页的结构可能会随着时间的推移而发生变化。因此,需要定期更新爬虫程序,以适应这些变化。
法律法规: 在爬取网页时,需要遵守法律法规和网站的robots协议。避免爬取敏感信息或者侵犯版权。
资源管理: 网络爬虫需要消耗大量的资源(如内存、CPU、带宽等)。如何有效地管理这些资源,以提高爬虫的性能和效率是一个挑战。数据清洗与去重: 抓取到的数据需要进行清洗和去重,这可能会花费大量的时间和资源。如何优化这一过程也是需要解决的问题。
应对动态网页和AJAX: 一些网页使用了动态加载技术(如AJAX),这使得爬虫难以抓取到完整的内容。需要使用一些技术(如Selenium)来模拟用户浏览网页的过程。
主要用到的工具-Selenium :Selenium是一个用于自动化网页浏览器交互的工具。它可以模拟真实的用户操作,如点击、输入、滚动等,并可用于测试网页应用程序。Python 是一种常用的编程语言,与 Selenium 结合使用,可以实现自动化测试和网页抓取等功能。
三、主题页面的结构特征分析:
节点标签的遍历与查找方法:
安装:pip install lxml,
遍历标签:使用lxml的XPath表达式,可以轻松地遍历和查找节点。例如,root.xpath('//div')
将返回页面中所有的<div>
标签,查找特定标签:使用XPath的谓词,可以进一步筛选符合条件的标签。例如,root.xpath('//div[@class="my-class"]')
将返回所有具有类名为my-class
的<div>
标签。
四、网络爬虫程序设计:
1.在craw_urls()方法里面定义获取cookies数组
1 # 获取cookies 2 cookies = [{'domain': '.taobao.com', 'expiry': 1718975586, 'httpOnly': False, 'name': 'tfstk', 'path': '/', 3 'sameSite': 'Lax', 'secure': False, 4 'value': 'eCj2nSbKjoEq3mMCuUxwYuJWm-KvXHFQ0GO6IOXMhIADGOvMb_f_HI6gM1SwZOQbHFNxQxIPTcibMrBibhtgOWZQAtpvXhVIp8TqatLme8Z7Ak6AnhKgOWZQHAQP_GdKjGj6nyy84hiupgJ2oz6DZcvR4K82tt0sjcDp3ERhnQjzOfpoG_SOuf0woLpyO8yymNrWaklfpyutWUxpUBwXhV39oLpyO8yrWVLkwLRQhK1..'}, 5 {'domain': '.taobao.com', 'expiry': 1718975585, 'httpOnly': False, 'name': 'l', 'path': '/', 6 'sameSite': 'Lax', 'secure': False, 7 'value': 'fBNPK_2lPXrmAhPLBOfaFurza77OSIRYYuPzaNbMi9fP_H5B5dhcW1CO4HL6C3GVF6x2R3JN2NiWBeYBqQAonxv92j-la_kmndLHR35..'}, 8 {'domain': '.taobao.com', 'expiry': 1718975581, 'httpOnly': False, 'name': 'isg', 'path': '/', 9 'sameSite': 'Lax', 'secure': False, 10 'value': 'BLi41pT5KZMAK0UXjCY4zKBjiWZKIRyr2ftmPfIpBPOmDVj3mjHsO84vwQW9XdSD'}, 11 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_nk_', 'path': '/', 'sameSite': 'None', 12 'secure': True, 'value': 'tb8886888261'}, 13 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_l_g_', 'path': '/', 'sameSite': 'None', 14 'secure': True, 'value': 'Ug%3D%3D'}, 15 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie1', 'path': '/', 'sameSite': 'None', 16 'secure': True, 'value': 'Uoe1g878%2FXBZ5ukZafynxMfy5m1Nw0TSusn7mxrZv8o%3D'}, 17 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'dnk', 'path': '/', 'sameSite': 'None', 18 'secure': True, 'value': 'tb8886888261'}, 19 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'cancelledSubSites', 'path': '/', 20 'sameSite': 'None', 'secure': True, 'value': 'empty'}, 21 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'sg', 'path': '/', 'sameSite': 'None', 22 'secure': True, 'value': '13d'}, 23 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': False, 'name': 'lgc', 'path': '/', 24 'sameSite': 'None', 'secure': True, 'value': 'tb8886888261'}, 25 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'csg', 'path': '/', 'sameSite': 'None', 26 'secure': True, 'value': '021b94b1'}, 27 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'skt', 'path': '/', 'sameSite': 'None', 28 'secure': True, 'value': 'b814e35f804c4129'}, 29 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': True, 'name': 'uc4', 'path': '/', 30 'sameSite': 'None', 'secure': True, 31 'value': 'id4=0%40U2gqztqLOvMR1igxs5TR4IHv0sMjRmW8&nk4=0%40FY4GunwKxg3bnnVtvdt4phAfXrriqlE%3D'}, 32 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie2', 'path': '/', 'sameSite': 'None', 33 'secure': True, 'value': '1d47d9380117510b45a916ce3fd7151c'}, 34 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': True, 'name': 'sgcookie', 'path': '/', 35 'sameSite': 'None', 'secure': True, 36 'value': 'E100WiXRlTwmfw8XKE9hipSUN9d%2FfKBVZuzs5qA6B47XstQ9a37rjnw6%2B79xrXwAxrq7a4EiBNJ2z%2FpVgIS2JFFhYcjFd1LimXUpCcu5VKAqgQY%3D'}, 37 {'domain': '.taobao.com', 'httpOnly': True, 'name': '_samesite_flag_', 'path': '/', 'sameSite': 'None', 38 'secure': True, 'value': 'true'}, 39 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'uc1', 'path': '/', 'sameSite': 'None', 40 'secure': True, 41 'value': 'pas=0&cookie14=UoYelq0xTPjuIw%3D%3D&cookie15=UtASsssmOIJ0bQ%3D%3D&existShop=false&cookie21=V32FPkk%2FhSg%2F&cookie16=VT5L2FSpNgq6fDudInPRgavC%2BQ%3D%3D'}, 42 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': False, 'name': '_cc_', 'path': '/', 43 'sameSite': 'None', 'secure': True, 'value': 'V32FPkk%2Fhw%3D%3D'}, 44 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie17', 'path': '/', 'sameSite': 'None', 45 'secure': True, 'value': 'UUpgQcOmU2CHjNIFhg%3D%3D'}, 46 {'domain': 's.taobao.com', 'httpOnly': True, 'name': 'JSESSIONID', 'path': '/', 'sameSite': 'Lax', 47 'secure': False, 'value': '3033B9AFAC54C6B25EAD0DEFA4995293'}, 48 {'domain': '.taobao.com', 'expiry': 1703682756, 'httpOnly': False, 'name': 'xlly_s', 'path': '/', 49 'sameSite': 'None', 'secure': True, 'value': '1'}, 50 {'domain': '.taobao.com', 'expiry': 1711228380, 'httpOnly': False, 'name': 't', 'path': '/', 51 'sameSite': 'None', 'secure': True, 'value': 'c65a1ed1d26940f48534dfc823cc5c0f'}, 52 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': False, 'name': 'tracknick', 'path': '/', 53 'sameSite': 'None', 'secure': True, 'value': 'tb8886888261'}, 54 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'unb', 'path': '/', 'sameSite': 'None', 55 'secure': True, 'value': '2217163630523'}, 56 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': True, 'name': 'uc3', 'path': '/', 57 'sameSite': 'None', 'secure': True, 58 'value': 'lg2=W5iHLLyFOGW7aA%3D%3D&nk2=F5RNbe%2FqJfGTSvcf&vt3=F8dD3Cb0K%2Fe5EA9lWwo%3D&id2=UUpgQcOmU2CHjNIFhg%3D%3D'}, 59 {'domain': '.taobao.com', 'expiry': 1737983560, 'httpOnly': False, 'name': 'cna', 'path': '/', 60 'sameSite': 'None', 'secure': True, 'value': 'RxwPHu/nrhwCAd5NNj0VKNeb'}, 61 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'existShop', 'path': '/', 'sameSite': 'None', 62 'secure': True, 'value': 'MTcwMzQyMzU4NQ%3D%3D'}, 63 {'domain': '.taobao.com', 'expiry': 1704028354, 'httpOnly': False, 'name': '_m_h5_tk', 'path': '/', 64 'sameSite': 'None', 'secure': True, 'value': '2ea9e31decb3f912ff6ba504d803cdb1_1703432198764'}, 65 {'domain': '.taobao.com', 'expiry': 1704028354, 'httpOnly': False, 'name': '_m_h5_tk_enc', 'path': '/', 66 'sameSite': 'None', 'secure': True, 'value': '4d83c19e396472df71233ec316f89e3f'}, 67 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_tb_token_', 'path': '/', 'sameSite': 'None', 68 'secure': True, 'value': 'f978137b5406e'}] 69 70 url = "https://s.taobao.com/search?commend=all&ie=utf8&initiative_id=tbindexz_20170306&q=%E6%84%9F%E5%86%92%E8%8D%AF&search_type=item&sourceId=tb.index&spm=a21bo.jianhua.201856-taobao-item.2&ssid=s5-e" 71 # driver1登录网站,获得cookie并保存
2.数据爬取与采集:使用while循环并且间隔两秒来爬取100个页面的商品信息
1 while True: 2 time.sleep(2) 3 driver.execute_script("document.documentElement.scrollTop=620") 4 div_list = driver.find_element(By.CLASS_NAME, 'Content--contentInner--QVTcU0M').find_elements(By.XPATH, "./div") 5 print("有" + str(len(div_list)) + "条") 6 if len(div_list) != 48: 7 print("当前页出错") 8 time.sleep(100) 9 for div in div_list: 10 # 以下为获取信息 11 link = div.find_element(By.XPATH, './a').get_attribute('href') 12 describe = div.find_element(By.CLASS_NAME, 'Title--title--jCOPvpf').text 13 pricea = div.find_element(By.CLASS_NAME, 'Price--priceInt--ZlsSi_M').text 14 priceb = div.find_element(By.CLASS_NAME, 'Price--priceFloat--h2RR0RK').text 15 price = pricea + priceb 16 business = div.find_element(By.XPATH, './a/div/div[3]/div[1]/a').text 17 location = div.find_element(By.CLASS_NAME, 'Price--priceWrapper--Q0Dn7pN ').find_element(By.XPATH, 18 './div').text 19 try: 20 sales = div.find_element(By.CLASS_NAME, 'Price--realSales--FhTZc7U').text 21 if sales: 22 sales = find_num(sales) 23 else: 24 sales = 0 25 except: 26 sales = 0 27 # 写入csv 28 writer.writerow([link, describe, price, business, location, sales]) 29 i += 1 30 # print(link,describe,price,business) 31 try: 32 # 以下为点击下一页 33 button_next = driver.find_element(By.XPATH, 34 '/html/body/div[2]/div/div[3]/div[1]/div[1]/div[2]/div[4]/div/div/button[2]') 35 if button_next.is_enabled(): 36 now = driver.find_element(By.XPATH, 37 '/html/body/div[2]/div/div[3]/div[1]/div[1]/div[2]/div[4]/div/div/span[1]/em').text 38 print("当前页:" + now) 39 button_next.click() 40 # print('点击') 41 else: 42 print("共计" + str(i) + "条信息") 43 break 44 except Exception: 45 slider(driver)
数据爬取完毕,程序运行结束,总共爬取了4800条商品信息。
3. 因为如果频繁的向淘宝服务器发送页面请求获取数据,淘宝会有一个滑块验证机制,所以定义了一个slider方法用来进行对弹出滑块提示框的验证,以此来继续进行下一个页面的获取
1 # 该方法主要用于处理滑块验证码 2 def slider(driver): 3 try: 4 print("准备进入frame") 5 driver.switch_to.frame(driver.find_element(By.XPATH, '/html/body/div[5]/iframe|/html/body/div[4]/iframe')) 6 print("进入frame") 7 actions = ActionChains(driver) 8 while True: 9 slider = driver.find_element(By.ID, 'nc_1_n1z') 10 print('找到滑块') 11 12 actions.click_and_hold(slider).perform() 13 x = random.randint(60, 140) # 每次移动60到140像素 14 # 移动小滑块,模拟人的操作,一次次移动一点点 15 actions.move_by_offset(xoffset=x, yoffset=0).perform() 16 time.sleep(0.2) 17 actions.move_by_offset(xoffset=300 - x, yoffset=0).perform() 18 # 移动完之后,松开鼠标 19 actions.release().perform() 20 try: 21 wrong = driver.find_element(By.ID, '`nc_1_refresh1`') 22 print("点击滑块") 23 wrong.click() 24 except: 25 print("成功") 26 print("出去frame") 27 driver.switch_to.default_content() 28 break 29 except Exception: 30 print("出去frame") 31 driver.switch_to.default_content() 32 33 34 def find_num(text): 35 # 正则表达式,用于匹配数字 36 pattern = r'\d+' 37 # 使用re.search查找匹配的数字 38 match = re.search(pattern, text) 39 # 如果找到匹配的数字,则输出 40 if match: 41 return match.group()
4.对数据进行保存,保存到csv文件,再手动到处为xlsx文件进行保存,保存文件名为淘宝感冒药.csv
1 # selenium伪装 2 with open("stealth.min.js") as f: 3 js = f.read() 4 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": js}) 5 6 data_file = open('淘宝感冒药' + '.csv', 'w', encoding='utf-8', newline='') 7 writer = csv.writer(data_file) 8 writer.writerow(['链接', "描述", "价格", "店铺", "所在地", "销量"]) 9 10 driver.get(url) 11 driver.maximize_window() 12 # 删除原来cookie 13 driver.delete_all_cookies() 14 # 添加cookie 15 for cookie in cookies: 16 if "expiry" in cookie: 17 del cookie["expiry"] 18 driver.add_cookie(cookie) 19 20 print("刷新") 21 driver.get(url) 22 time.sleep(3)
5.数据可视化 通过读取淘宝感冒药.csv文件来绘制直方图
1 # 直方图 2 def histogram(): 3 # 读取CSV文件 4 df = pd.read_csv('淘宝感冒药.csv') 5 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 6 # 确保省份列和销售量列的名称正确 7 province_column = '所在地' 8 sales_column = '销量' 9 # 计算每个省份的总销售量 10 province_sales = df.groupby(province_column)[sales_column].sum().sort_values(ascending=False) 11 # 绘制直方图 12 province_sales.plot(kind='bar', figsize=(10, 6)) 13 # 设置横坐标标签为省份,纵坐标标签为总销售量 14 plt.xlabel(province_column) 15 plt.ylabel(sales_column) 16 # 显示图例 17 plt.legend([sales_column]) 18 # 显示图表 19 plt.show()
通过直方图明显可以看出广东的感冒药销量位居首位,全国的大部分淘宝用户购买感冒的药品都是从广东的药店进行网购,由此得出广东省总体感冒药品出售量是最大的,整体来说也是卖的最好的。
6.通过调用scatter()方法绘制散点图
1 # 点图 2 def scatter(): 3 # 读取CSV文件 4 df = pd.read_csv('淘宝感冒药.csv') 5 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 6 # 确保省份列和销售量列的正确名称 7 province_column = '所在地' 8 sales_column = '销量' 9 10 # 计算每个省份的总销售量 11 province_sales = df.groupby(province_column)[sales_column].sum().reset_index() 12 # 绘制点图 13 province_sales.plot(kind='scatter', x=province_column, y=sales_column, figsize=(10, 6)) 14 # 设置图表标题和轴标签 15 plt.title('省份销售量点图') 16 plt.xlabel('省份') 17 plt.ylabel('总销售量') 18 # 显示图表 19 plt.show()
7.通过调用line()方法绘制折线图
(1)所在地与销量
1 # 折线图 2 def line(): 3 # 读取CSV文件 4 df = pd.read_csv('淘宝感冒药.csv') 5 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 6 # 确保省份列和销售量列的正确名称 7 province_column = '所在地' 8 sales_column = '销量' 9 # 计算每个省份的总销售量 10 province_sales = df.groupby(province_column)[sales_column].sum().reset_index() 11 # 绘制折线图 12 province_sales.plot(kind='line', x=province_column, y=sales_column, figsize=(10, 6)) 13 # 设置图表标题和轴标签 14 plt.title('省份总销售量折线图') 15 plt.xlabel('省份') 16 plt.ylabel('总销售量') 17 # 显示图表 18 plt.show()
(1)店铺与销量
1 # 折线图 2 def line(): 3 # 读取CSV文件 4 df = pd.read_csv('淘宝感冒药.csv') 5 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 6 7 # 确保省份列和销售量列的正确名称 8 province_column = '店铺' 9 sales_column = '销量' 10 11 # 筛选出每个省份销量大于750的数据 12 filtered_df = df[(df[province_column].duplicated(keep='first') == False) & (df[sales_column] > 750)] 13 14 # 计算每个省份的总销售量 15 province_sales = filtered_df.groupby(province_column)[sales_column].sum().reset_index() 16 17 # 绘制折线图 18 province_sales.plot(kind='line', x=province_column, y=sales_column, figsize=(10, 6)) 19 20 # 设置图表标题和轴标签 21 plt.title('省份总销售量折线图(销量大于750)') 22 plt.xlabel('省份') 23 plt.ylabel('总销售量') 24 25 # 显示图表 26 plt.show()
8.通过调用pie()方法绘制饼图
1 #绘制饼图 2 def pie(): 3 # 读取CSV文件 4 df = pd.read_csv('淘宝感冒药.csv') 5 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 6 7 # 筛选条件,例如选择销量大于100的店铺 8 filtered_df = df[df['销量'] > 750] 9 10 # 确保店铺列和销量列的名称正确 11 shop_column = '所在地' 12 sales_column = '销量' 13 14 # 计算筛选后每个店铺的总销售量并转换为浮点数 15 shop_sales = filtered_df.groupby(shop_column)[sales_column].sum().astype(float).sort_values(ascending=False) 16 17 # 绘制饼图 18 fig, ax = plt.subplots() 19 ax.pie(shop_sales, labels=shop_sales.index, autopct='%1.1f%%', startangle=180) 20 21 # 设置标题和确保饼图是圆形 22 ax.set_title('淘宝感冒药销量饼图(销量大于750)') 23 ax.axis('equal') 24 25 # 显示图表 26 plt.show()
完整代码如下:
1 # 导入相关模块 2 import csv 3 import random 4 import re 5 import time 6 import matplotlib 7 import pandas as pd 8 import matplotlib.pyplot as plt 9 10 #导入Selenium库中的类和模块,主要用于网页自动化测试和操作 11 from selenium.webdriver.common.by import By 12 from selenium.webdriver import Edge, ActionChains 13 from selenium.webdriver.edge.options import Options 14 15 16 # 该方法主要用于获取淘宝cookie信息,运行该方法需要我们在15秒内用手机淘宝扫码登录,等到控制台打印出来cookie后手动停止该方法 17 def get_cookies(): 18 # 设置URL,定义一个淘宝网页的URL用来搜索感冒药的页面 19 url = "https://s.taobao.com/search?commend=all&ie=utf8&initiative_id=tbindexz_20170306&q=%E6%84%9F%E5%86%92%E8%8D%AF&search_type=item&sourceId=tb.index&spm=a21bo.jianhua.201856-taobao-item.2&ssid=s5-e" 20 edge_options = Options() 21 # 使用chromium内核,打开开发者模式 22 edge_options.use_chromium = True 23 # 添加参数 24 edge_options.add_argument('--disable-blink-features=AutomationControlled') 25 # 将参数配置到web对象 26 web = Edge(options=edge_options) 27 #打开定义的URL 28 web.get(url) 29 #让程序暂停20秒,为了确保页面完全加载。 30 time.sleep(20) 31 #从当前浏览器实例中获取所有的cookies 32 cookies = web.get_cookies() 33 #打印获取到的cookies 34 print(cookies) 35 #程序暂停100秒 36 time.sleep(100) 37 38 39 # 该方法主要用于处理滑块验证码 40 def slider(driver): 41 try: 42 print("准备进入frame") 43 # 切换到指定的iframe,使用复合的XPath表达式来定位iframe。 44 driver.switch_to.frame(driver.find_element(By.XPATH, '/html/body/div[5]/iframe|/html/body/div[4]/iframe')) 45 print("进入frame") 46 #创建一个新的ActionChains对象 47 actions = ActionChains(driver) 48 while True: 49 slider = driver.find_element(By.ID, 'nc_1_n1z') 50 print('找到滑块') 51 #在滑块上点击并保持不放 52 actions.click_and_hold(slider).perform() 53 #生成一个随机数,范围在60到140之间,用于模拟滑块的随机移动 54 x = random.randint(60, 140) # 每次移动60到140像素 55 56 # 移动小滑块,模拟人的操作,一次次移动一点点 57 actions.move_by_offset(xoffset=x, yoffset=0).perform() 58 time.sleep(0.2) 59 actions.move_by_offset(xoffset=300 - x, yoffset=0).perform() 60 61 # 移动完之后,松开鼠标 62 actions.release().perform() 63 #异常处理 64 try: 65 #查找具有ID为'nc_1_refresh1'的元素 66 wrong = driver.find_element(By.ID, '`nc_1_refresh1`') 67 print("点击滑块") 68 # 点击找到的元素 69 wrong.click() 70 except: 71 print("成功") 72 print("出去frame") 73 driver.switch_to.default_content() 74 break 75 except Exception: 76 print("出去frame") 77 #切换回默认内容 78 driver.switch_to.default_content() 79 80 81 def find_num(text): 82 # 正则表达式,用于匹配数字 83 pattern = r'\d+' 84 # 使用re.search查找匹配的数字 85 match = re.search(pattern, text) 86 # 如果找到匹配的数字,则输出 87 if match: 88 return match.group() 89 90 91 def craw_urls(): 92 # 获取并打印淘宝(Taobao)网站的cookies,这里使用了Selenium库来控制一个Edge浏览器实例,并且访问特定的URL 93 cookies = [{'domain': '.taobao.com', 'expiry': 1718975586, 'httpOnly': False, 'name': 'tfstk', 'path': '/', 94 'sameSite': 'Lax', 'secure': False, 95 'value': 'eCj2nSbKjoEq3mMCuUxwYuJWm-KvXHFQ0GO6IOXMhIADGOvMb_f_HI6gM1SwZOQbHFNxQxIPTcibMrBibhtgOWZQAtpvXhVIp8TqatLme8Z7Ak6AnhKgOWZQHAQP_GdKjGj6nyy84hiupgJ2oz6DZcvR4K82tt0sjcDp3ERhnQjzOfpoG_SOuf0woLpyO8yymNrWaklfpyutWUxpUBwXhV39oLpyO8yrWVLkwLRQhK1..'}, 96 {'domain': '.taobao.com', 'expiry': 1718975585, 'httpOnly': False, 'name': 'l', 'path': '/', 97 'sameSite': 'Lax', 'secure': False, 98 'value': 'fBNPK_2lPXrmAhPLBOfaFurza77OSIRYYuPzaNbMi9fP_H5B5dhcW1CO4HL6C3GVF6x2R3JN2NiWBeYBqQAonxv92j-la_kmndLHR35..'}, 99 {'domain': '.taobao.com', 'expiry': 1718975581, 'httpOnly': False, 'name': 'isg', 'path': '/', 100 'sameSite': 'Lax', 'secure': False, 101 'value': 'BLi41pT5KZMAK0UXjCY4zKBjiWZKIRyr2ftmPfIpBPOmDVj3mjHsO84vwQW9XdSD'}, 102 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_nk_', 'path': '/', 'sameSite': 'None', 103 'secure': True, 'value': 'tb8886888261'}, 104 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_l_g_', 'path': '/', 'sameSite': 'None', 105 'secure': True, 'value': 'Ug%3D%3D'}, 106 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie1', 'path': '/', 'sameSite': 'None', 107 'secure': True, 'value': 'Uoe1g878%2FXBZ5ukZafynxMfy5m1Nw0TSusn7mxrZv8o%3D'}, 108 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'dnk', 'path': '/', 'sameSite': 'None', 109 'secure': True, 'value': 'tb8886888261'}, 110 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'cancelledSubSites', 'path': '/', 111 'sameSite': 'None', 'secure': True, 'value': 'empty'}, 112 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'sg', 'path': '/', 'sameSite': 'None', 113 'secure': True, 'value': '13d'}, 114 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': False, 'name': 'lgc', 'path': '/', 115 'sameSite': 'None', 'secure': True, 'value': 'tb8886888261'}, 116 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'csg', 'path': '/', 'sameSite': 'None', 117 'secure': True, 'value': '021b94b1'}, 118 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'skt', 'path': '/', 'sameSite': 'None', 119 'secure': True, 'value': 'b814e35f804c4129'}, 120 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': True, 'name': 'uc4', 'path': '/', 121 'sameSite': 'None', 'secure': True, 122 'value': 'id4=0%40U2gqztqLOvMR1igxs5TR4IHv0sMjRmW8&nk4=0%40FY4GunwKxg3bnnVtvdt4phAfXrriqlE%3D'}, 123 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie2', 'path': '/', 'sameSite': 'None', 124 'secure': True, 'value': '1d47d9380117510b45a916ce3fd7151c'}, 125 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': True, 'name': 'sgcookie', 'path': '/', 126 'sameSite': 'None', 'secure': True, 127 'value': 'E100WiXRlTwmfw8XKE9hipSUN9d%2FfKBVZuzs5qA6B47XstQ9a37rjnw6%2B79xrXwAxrq7a4EiBNJ2z%2FpVgIS2JFFhYcjFd1LimXUpCcu5VKAqgQY%3D'}, 128 {'domain': '.taobao.com', 'httpOnly': True, 'name': '_samesite_flag_', 'path': '/', 'sameSite': 'None', 129 'secure': True, 'value': 'true'}, 130 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'uc1', 'path': '/', 'sameSite': 'None', 131 'secure': True, 132 'value': 'pas=0&cookie14=UoYelq0xTPjuIw%3D%3D&cookie15=UtASsssmOIJ0bQ%3D%3D&existShop=false&cookie21=V32FPkk%2FhSg%2F&cookie16=VT5L2FSpNgq6fDudInPRgavC%2BQ%3D%3D'}, 133 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': False, 'name': '_cc_', 'path': '/', 134 'sameSite': 'None', 'secure': True, 'value': 'V32FPkk%2Fhw%3D%3D'}, 135 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'cookie17', 'path': '/', 'sameSite': 'None', 136 'secure': True, 'value': 'UUpgQcOmU2CHjNIFhg%3D%3D'}, 137 {'domain': 's.taobao.com', 'httpOnly': True, 'name': 'JSESSIONID', 'path': '/', 'sameSite': 'Lax', 138 'secure': False, 'value': '3033B9AFAC54C6B25EAD0DEFA4995293'}, 139 {'domain': '.taobao.com', 'expiry': 1703682756, 'httpOnly': False, 'name': 'xlly_s', 'path': '/', 140 'sameSite': 'None', 'secure': True, 'value': '1'}, 141 {'domain': '.taobao.com', 'expiry': 1711228380, 'httpOnly': False, 'name': 't', 'path': '/', 142 'sameSite': 'None', 'secure': True, 'value': 'c65a1ed1d26940f48534dfc823cc5c0f'}, 143 {'domain': '.taobao.com', 'expiry': 1734988380, 'httpOnly': False, 'name': 'tracknick', 'path': '/', 144 'sameSite': 'None', 'secure': True, 'value': 'tb8886888261'}, 145 {'domain': '.taobao.com', 'httpOnly': True, 'name': 'unb', 'path': '/', 'sameSite': 'None', 146 'secure': True, 'value': '2217163630523'}, 147 {'domain': '.taobao.com', 'expiry': 1706044380, 'httpOnly': True, 'name': 'uc3', 'path': '/', 148 'sameSite': 'None', 'secure': True, 149 'value': 'lg2=W5iHLLyFOGW7aA%3D%3D&nk2=F5RNbe%2FqJfGTSvcf&vt3=F8dD3Cb0K%2Fe5EA9lWwo%3D&id2=UUpgQcOmU2CHjNIFhg%3D%3D'}, 150 {'domain': '.taobao.com', 'expiry': 1737983560, 'httpOnly': False, 'name': 'cna', 'path': '/', 151 'sameSite': 'None', 'secure': True, 'value': 'RxwPHu/nrhwCAd5NNj0VKNeb'}, 152 {'domain': '.taobao.com', 'httpOnly': False, 'name': 'existShop', 'path': '/', 'sameSite': 'None', 153 'secure': True, 'value': 'MTcwMzQyMzU4NQ%3D%3D'}, 154 {'domain': '.taobao.com', 'expiry': 1704028354, 'httpOnly': False, 'name': '_m_h5_tk', 'path': '/', 155 'sameSite': 'None', 'secure': True, 'value': '2ea9e31decb3f912ff6ba504d803cdb1_1703432198764'}, 156 {'domain': '.taobao.com', 'expiry': 1704028354, 'httpOnly': False, 'name': '_m_h5_tk_enc', 'path': '/', 157 'sameSite': 'None', 'secure': True, 'value': '4d83c19e396472df71233ec316f89e3f'}, 158 {'domain': '.taobao.com', 'httpOnly': False, 'name': '_tb_token_', 'path': '/', 'sameSite': 'None', 159 'secure': True, 'value': 'f978137b5406e'}] 160 #这个URL是用来在淘宝网上搜索“感冒”相关商品的 161 url = "https://s.taobao.com/search?commend=all&ie=utf8&initiative_id=tbindexz_20170306&q=%E6%84%9F%E5%86%92%E8%8D%AF&search_type=item&sourceId=tb.index&spm=a21bo.jianhua.201856-taobao-item.2&ssid=s5-e" 162 # driver1登录网站,获得cookie并保存 163 #创建一个新的Selenium选项对象 164 options = Options() 165 #设置选项,指示使用Chromium作为web渲染引擎,Microsoft Edge浏览器基于Chromium构建 166 options.use_chromium = True 167 # 向web浏览器添加命令行参数,这通常用于避免某些与自动化控制相关的功能被禁用 168 options.add_argument("--disable-blink-features=AutomationControlled") 169 # options.add_argument("--headless") 170 #使用上面定义的选项创建一个新的Edge浏览器实例 171 driver = Edge(options=options) 172 #设置隐式等待时间,单位为秒 173 driver.implicitly_wait(10) 174 # selenium伪装 175 #保存数据到csv文件中 176 with open("stealth.min.js") as f: 177 js = f.read() 178 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": js}) 179 180 data_file = open('淘宝感冒药' + '.csv', 'w', encoding='utf-8', newline='') 181 writer = csv.writer(data_file) 182 writer.writerow(['链接', "描述", "价格", "店铺", "所在地", "销量"]) 183 184 #打开一个指定的URL,driver是一个Selenium WebDriver的实例,它代表一个浏览器窗口。 185 driver.get(url) 186 #最大化浏览器窗口 187 driver.maximize_window() 188 # 删除原来cookie 189 driver.delete_all_cookies() 190 # 遍历cookies列表,添加到浏览器中的cookie字典 191 for cookie in cookies: 192 if "expiry" in cookie: 193 del cookie["expiry"] 194 driver.add_cookie(cookie) 195 196 print("刷新") 197 #使用Selenium WebDriver打开指定的URL 198 driver.get(url) 199 #等待3秒 200 time.sleep(3) 201 #调用slider函数,该函数可能是用于处理页面上的滑块验证 202 slider(driver) 203 i = 0 204 while True: 205 time.sleep(2) 206 #使用JavaScript来滚动页面到指定位置 207 driver.execute_script("document.documentElement.scrollTop=620") 208 #查找页面上的特定元素,并获取其子div元素列表。 209 div_list = driver.find_element(By.CLASS_NAME, 'Content--contentInner--QVTcU0M').find_elements(By.XPATH, "./div") 210 print("有" + str(len(div_list)) + "条") 211 #检查当前页面的div元素数量是否与预期的数量(48)不符 212 if len(div_list) != 48: 213 print("当前页出错") 214 time.sleep(100) 215 #循环遍历每一个div元素 216 for div in div_list: 217 #使用XPath查找并获取链接、描述、价格、商家、位置和销量等信息 218 link = div.find_element(By.XPATH, './a').get_attribute('href') 219 describe = div.find_element(By.CLASS_NAME, 'Title--title--jCOPvpf').text 220 pricea = div.find_element(By.CLASS_NAME, 'Price--priceInt--ZlsSi_M').text 221 priceb = div.find_element(By.CLASS_NAME, 'Price--priceFloat--h2RR0RK').text 222 price = pricea + priceb 223 business = div.find_element(By.XPATH, './a/div/div[3]/div[1]/a').text 224 location = div.find_element(By.CLASS_NAME, 'Price--priceWrapper--Q0Dn7pN ').find_element(By.XPATH, 225 './div').text 226 try: 227 #查找具有特定类名的元素 228 sales = div.find_element(By.CLASS_NAME, 'Price--realSales--FhTZc7U').text 229 if sales: 230 #如果销售数量不为空,调用find_num函数将销售数量转换为数字 231 sales = find_num(sales) 232 else: 233 #如果销售数量为空或不存在,将销售数量设置为0 234 sales = 0 235 except: 236 #如果出现异常,将销售数量设置为0 237 sales = 0 238 # 写入csv 239 writer.writerow([link, describe, price, business, location, sales]) 240 i += 1 241 # print(link,describe,price,business) 242 try: 243 # 以下为点击下一页 使用XPath查找下一页按钮 244 button_next = driver.find_element(By.XPATH,'/html/body/div[2]/div/div[3]/div[1]/div[1]/div[2]/div[4]/div/div/button[2]') 245 # 检查下一页按钮是否启用 246 if button_next.is_enabled(): 247 #使用XPath查找当前页码,并获取其文本内容 248 now = driver.find_element(By.XPATH,'/html/body/div[2]/div/div[3]/div[1]/div[1]/div[2]/div[4]/div/div/span[1]/em').text 249 #打印当前页码 250 print("当前页:" + now) 251 #点击下一页按钮 252 button_next.click() 253 # print('点击') 254 else: 255 #打印已获取的信息数量并跳出循环 256 print("共计" + str(i) + "条信息") 257 break 258 except Exception: 259 #重新处理滑块 260 slider(driver) 261 262 263 # 直方图 264 def histogram(): 265 # 读取CSV文件 266 df = pd.read_csv('淘宝感冒药.csv') 267 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 268 # 确保省份列和销售量列的名称正确 269 province_column = '所在地' 270 sales_column = '销量' 271 # 计算每个省份的总销售量 272 province_sales = df.groupby(province_column)[sales_column].sum().sort_values(ascending=False) 273 # 绘制直方图 274 province_sales.plot(kind='bar', figsize=(10, 6)) 275 # 设置横坐标标签为省份,纵坐标标签为总销售量 276 plt.xlabel(province_column) 277 plt.ylabel(sales_column) 278 # 显示图例 279 plt.legend([sales_column]) 280 # 显示图表 281 plt.show() 282 283 284 #绘制饼图 285 def pie(): 286 # 读取CSV文件 287 df = pd.read_csv('淘宝感冒药.csv') 288 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 289 290 # 筛选条件,例如选择销量大于100的店铺 291 filtered_df = df[df['销量'] > 750] 292 293 # 确保店铺列和销量列的名称正确 294 shop_column = '所在地' 295 sales_column = '销量' 296 297 # 计算筛选后每个店铺的总销售量并转换为浮点数 298 shop_sales = filtered_df.groupby(shop_column)[sales_column].sum().astype(float).sort_values(ascending=False) 299 300 # 绘制饼图 301 fig, ax = plt.subplots() 302 ax.pie(shop_sales, labels=shop_sales.index, autopct='%1.1f%%', startangle=180) 303 304 # 设置标题和确保饼图是圆形 305 ax.set_title('淘宝感冒药销量饼图(销量大于750)') 306 ax.axis('equal') 307 308 # 显示图表 309 plt.show() 310 311 # 点图 312 def scatter(): 313 # 读取CSV文件 314 df = pd.read_csv('淘宝感冒药.csv') 315 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 316 # 确保省份列和销售量列的正确名称 317 province_column = '所在地' 318 sales_column = '销量' 319 320 # 计算每个省份的总销售量 321 province_sales = df.groupby(province_column)[sales_column].sum().reset_index() 322 # 绘制点图 323 province_sales.plot(kind='scatter', x=province_column, y=sales_column, figsize=(10, 6)) 324 # 设置图表标题和轴标签 325 plt.title('省份销售量点图') 326 plt.xlabel('省份') 327 plt.ylabel('总销售量') 328 # 显示图表 329 plt.show() 330 331 # 折线图 所在地与销量 332 def line1(): 333 #读取CSV文件 334 df = pd.read_csv('淘宝感冒药.csv') 335 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 336 # 确保省份列和销售量列的正确名称 337 province_column = '所在地' 338 sales_column = '销量' 339 # 计算每个省份的总销售量 340 province_sales = df.groupby(province_column)[sales_column].sum().reset_index() 341 # 绘制折线图 342 province_sales.plot(kind='line', x=province_column, y=sales_column, figsize=(10, 6)) 343 # 设置图表标题和轴标签 344 plt.title('省份总销售量折线图') 345 plt.xlabel('省份') 346 plt.ylabel('总销售量') 347 # 显示图表 348 plt.show() 349 350 351 # 折线图 店铺与销量 352 def line2(): 353 # 读取CSV文件 354 df = pd.read_csv('淘宝感冒药.csv') 355 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 356 357 # 确保省份列和销售量列的正确名称 358 province_column = '店铺' 359 sales_column = '销量' 360 361 # 筛选出每个省份销量大于750的数据 362 filtered_df = df[(df[province_column].duplicated(keep='first') == False) & (df[sales_column] > 750)] 363 364 # 计算每个省份的总销售量 365 province_sales = filtered_df.groupby(province_column)[sales_column].sum().reset_index() 366 367 # 绘制折线图 368 province_sales.plot(kind='line', x=province_column, y=sales_column, figsize=(10, 6)) 369 370 # 设置图表标题和轴标签 371 plt.title('省份总销售量折线图(销量大于750)') 372 plt.xlabel('省份') 373 plt.ylabel('总销售量') 374 375 # 显示图表 376 plt.show() 377 378 # 运行下列方法,可得出对应结果 379 #cookies方法 380 get_cookies() 381 #调用craw_urls()方法 开始运行程序 382 craw_urls() 383 # 画柱状图 384 histogram() 385 # 画散点图 386 scatter() 387 #画折线图1 所在地与销量 388 line1() 389 #画折线图2 店铺与销量 390 line2() 391 #histogram2() 392 #画饼图 393 pie()
五、总结
1.
(1)数据获取与验证:Selenium可以帮助自动化地模拟用户浏览网页的行为,从而抓取动态生成或隐藏在JavaScript中的数据。通过分析这些数据,你可以了解网站的结构、内容、交互方式等信息,并进行数据验证,确保获取的数据是准确和可靠的。
(2)用户行为分析:通过Selenium,你可以记录用户在网站上的行为路径,包括点击、滑动、输入等操作。对这些行为进行分析,可以得出用户对网站内容的兴趣点、交互习惯等信息,有助于理解用户需求和行为模式。
(3)竞品对比:通过爬取和分析竞争对手的网站数据,你可以了解竞争对手的产品特点、价格策略、推广方式等信息,进而为自己的产品或服务提供优化和改进的依据。
(4)市场趋势预测:结合大数据分析方法,通过对大量历史数据的挖掘和分析,可以预测市场趋势和用户需求的变化,为企业的战略决策提供支持。
已经初步达到了预期的目标,能过获取商品的主要信息和数据。
2.
(1)收获:
增强了对Web开发和数据可视化的理解:通过实际操作,你会更深入地了解Web页面的结构和动态行为,以及如何将数据以直观的方式呈现出来。掌握自动化测试技能:Selenium不仅可以用于数据爬取,还可以用于自动化测试。通过编写测试脚本,你可以验证网站的功能和性能是否正常。
(2)改进建议:提升数据爬取效率:Selenium在处理动态网页时可能存在性能问题。为了提高数据爬取的效率,可以考虑使用其他工具或库,如Puppeteer或Pyppeteer等替代方案。加强数据安全保护:在爬取数据时,要确保遵守法律法规和网站的robots协议,避免对目标网站造成不必要的负担或法律风险。同时,要注意保护个人隐私和敏感信息。提升数据可视化效果:为了更好地呈现数据的特征和趋势,可以尝试使用更丰富的可视化技术,如热力图、散点图、时间序列图等。同时,要注意可视化设计的可读性和易理解性。加强数据源管理:确保数据的可靠性和一致性对于分析结果的准确性至关重要。因此,需要加强数据源的管理,定期检查和更新数据爬取的代码和配置。
lxml库