jjddrushi 2020-04-19
‘‘‘ 思路: 1. 打开浏览器,输入关键词搜索 2. 跳转至登录页面,使用微博登录 3. 登录完成获取列表页 4. 解析数据 5. 保存数据 ‘‘‘ import time import re import pymongo from pyquery import PyQuery as pq from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options # 这个包是导入配置包,里面可以存放数据库连接和关键词以及登录账号密码等常量 from settings import * # 将浏览器设置为无头浏览器 chrome_options = Options() chrome_options.add_argument("headless") chrome_options.add_argument("--disable-gpu") # 打开浏览器 chrome = webdriver.Chrome() # 为了保证不出错,定义一个显式等待变量 wait = WebDriverWait(chrome, 10) # 连接MongoDB client = pymongo.MongoClient(MONGO_URL) db = client[MONGO_DB] def search(): ‘‘‘ 此函数主要用来模拟登录以及获取第一页数据 ‘‘‘ try: chrome.get(‘https://www.taobao.com/‘) # 输入关键字点击搜索 input = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))) submit = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button"))) input.send_keys(KEY_WORD) time.sleep(1) submit.click() # 模拟登录(用微博登录) login = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, "#login-form > div.login-blocks.sns-login-links > a.weibo-login"))).click() chrome.find_element_by_xpath("//*[@id=‘pl_login_logged‘]/div/div[2]/div/input").send_keys(USERNAME) time.sleep(1) chrome.find_element_by_xpath("//*[@id=‘pl_login_logged‘]/div/div[3]/div/input").send_keys(PASSWORD) time.sleep(1) chrome.find_element_by_xpath("//*[@id=‘pl_login_logged‘]/div/div[7]/div[1]/a/span").click() # 获取总页数 total_page = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total"))) # 解析数据 注意:等待可以获取到底部总页数的时候,说明列表页已经加载完毕,可以开始解析数据 get_product() return total_page.text except TimeoutError: # 如果请求出错,递归调用自身,相当于retrying return search() def next_page(page_num): ‘‘‘ 这个函数用来请求列表页 ‘‘‘ try: # 请求下一页 input = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input"))) submit = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit")) ) input.clear() input.send_keys(page_num) submit.click() wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > ul > li.item.active > span"),str(page_num))) # 解析数据 get_product() except TimeoutError: next_page(page_num) def get_product(): ‘‘‘ 这个函数用来解析数据,解析库可以根据自己喜好更改 ‘‘‘ wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ‘#mainsrp-itemlist .items .item‘))) html = chrome.page_source doc = pq(html) items = doc(‘#mainsrp-itemlist .items .item‘).items() for item in items: product = { ‘image‘: item.find(‘.pic .img‘).attr(‘src‘), ‘price‘: item.find(‘.price‘).text(), ‘deal‘: item.find(‘.deal-cnt‘).text()[:-3], ‘title‘: item.find(‘.title‘).text().strip(), ‘shop‘: item.find(‘.shop‘).text(), ‘location‘: item.find(‘.location‘).text() } print(product) save_to_mongo(product) def save_to_mongo(result): ‘‘‘ 保存到MongoDB ‘‘‘ try: if db[MONGO_TABLE].insert_one(result): print(‘保存到MONGODB成功‘, result) except Exception: print(‘保存到MONGODB失败‘, result) def main(): ‘‘‘ 主要爬网逻辑 ‘‘‘ try: total = search() # 获取总页数 total = int(re.compile(‘(\d+)‘).search(total).group(1)) for i in range(2, total+1): next_page(i) except Exception: print(‘出错了‘) finally: chrome.close() if __name__ == ‘__main__‘: main()
以上代码不足之处,没有使用代理,淘宝网算是反爬比较厉害的网站,时不时会跳出来浏览限制(比如让输入验证码),一般都是因为同一个ip短时间内数据获取量太快
提供三个解决方案
1. 外接打码平台,识别验证码,返回输入
2. 如果比较牛逼,可以使用深度学习图像识别识别验证码输入
3. 使用代理,这个是个人觉得比较好的解决方案,从可行性和解决问题的本质上算比较优的解决方案
配置文件内容
微博账号和密码(微博要和淘宝是同一个手机号哦)
USERNAME = ‘‘
PASSWORD = ‘‘
MongoDB配置
MONGO_URL = ‘localhost‘
MONGO_DB = ‘taobao‘
MONGO_TABLE = ‘product‘
关键词
KEY_WORD = ‘美食‘