python selenium 爬取《全国农产品商务信息公共服务平台》

这是我参与的第二个项目,进程还是很顺利的。这也不断改进的过程,总共有三个版本:

  • 第一个版本是普通的爬取,对于某个农产品关键词,获取它全部的内容,后来由于我的网速太差,python运行报错了,每个农产品都拥有八百多个页面,如果重新开始,就会浪费很多时间,还不能确保它出错,于是我就改进成了第二个版本;
  • 第二个版本是对某个农产品定页爬取,爬取某个页数区间的产品,用来弥补第一个版本信息出错后,接着上次的页数爬取数据
  • 第三个版本是全自动化爬取;在第二个的基础上,浏览器的窗口总是弹出来干扰我做其他的事,所以就在这个版本中把浏览器隐藏起来,方便我工作。并且还加入随机验证码,实现全部自动化。

网址: http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml

1、开始前工作:

1.1、分析网页

可以把这个页面简单的理解成为一个查询接口,必须要输入验证码,点击搜索才能拿到数据,我经过简单的分析后,并没有找到数据的接口,所以就直接确定使用selenium来抓取数据了。
在这里插入图片描述

1.2、分析验证码

对于存在验证码的很多网页,如果使用验证码的次数不多,我们就可以直接使用手动输入,如果它不断的有验证码,就需要让它自动识别验证码了,但是我们爬取的这个网页验证码并不多,每种产品就只需要输入一次验证码,所以可以使用手动输入,但是重点来了,该网页经过我的测试,发现它的验证码并没有实际的作业,也就是说这个验证码可以随便输入数字,也就为我的第三个版本做铺垫了!

1.3、分析URL

虽然说URL对selenium后期的爬取作用不大,但是这个的URL隐藏了大量的信息:
在这里插入图片描述

  • 默认时间只有三个月,如果需要查看更多商品的话,自己可以去更改时间
  • 在接下来的爬取中,它只是页码会有变化,其他的数据都不会改变
  • 注意:不能直接在URL上使用起始页不为1的其他页数,因为输入验证码后都是数据都是从第一页开始的
  • 建议用selenium时,不要让URL携带验证码和页数

2、第一个版本——普通的爬取

2.1、代码汇总

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from lxml import etree
import time,xlwt

startTime =time.time()#记录开始时间
all_page = []#用来保存所有页面爬取到的数据
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
driver = webdriver.Chrome()
driver.implicitly_wait(5)
chrome_option = webdriver.ChromeOptions()
chrome_option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP
driver.get(url)#打开网页网页
driver.implicitly_wait(6)#等待加载六秒
time.sleep(10)

def next_page():
    for page in range(1,816,1):#从第1页爬取到第815页
        print ("~~~~~~~~~~正在爬取第%s页,一共有815页~~~~~~~~~"%page)
        if int(page) == 1:#当页码为1时,不需要点击下一页,直接跳转去获取html源码
            get_html()
        #点击下一页,下一页的a标签是最后一个标签
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()
        
def get_html():
    driver.implicitly_wait(5)#等待加载,完成后自动执行下一步
    source = driver.page_source#获取网页源代码
    html = etree.HTML(source)#lxml解析网页
    spider(html)
        
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')#商品
            price = tr.xpath('./td[3]/span/text()')#价格
            unit = tr.xpath('./td[3]/text()')#单位
            market = tr.xpath('./td[4]/a/text()')#市场
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]   #详情链接                     
            page = [time,goods,price,unit,market,link]#生成数组
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#创建工作簿
    sheet = book.add_sheet('生姜',cell_overwrite_ok=True)#创建表名,cell_overwrite_ok=True用于确认同一个cell单元是否可以重设值
    head = ['时间','产品','价格','单位','市场','链接']#定义表头,即Excel中第一行标题
    for h in range(len(head)):
        sheet.write(0,h,head[h])#写入表头

    j = 1#第一行开始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,并写入数据,重新设置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\农产品(生姜).xls')
    
if __name__ == '__main__':
    next_page()
    endTime =time.time()
    useTime =(endTime-startTime)/60
    print ("该次所获的信息一共使用%s分钟"%useTime)

2.2、运行代码后手段点击确定,并快速输入验证码

在这里插入图片描述
现在的浏览器属于被控制的状态,但是它是支持认为操作的。弹出浏览器后,该页面会先有一个弹窗,只用点击后才能输入验证码,这里的验证码可以随便输入四位数,如果怕手速不够快的话,可以在代码中多停一点时间,确保代码正常运行!

2.3、报错问题

如果你的环境运行这个代码有误,请检查一下你的电脑是否配置了chromedriver.exe,因为只是安装selenium是不够的,还需要配置浏览器的才行,如谷歌的需要下载对应版本的才行,没有的话可以移步去看看:
python selenium新手入门安装问题,这个方法可以不用配置环境,直接引用!

如果的pip配置过化境的话,简单来说可以这样做:

  1. http://npm.taobao.org/mirrors/chromedriver/下载对于自己浏览器的chromedriver.exe,我使用的是谷歌浏览器。
  2. 把你下载的chromedriver.exe复制到你安装python的script路径下,就算完成配置了。
  3. 有必要的话,可以重启电脑加载环境变量。
    运行结果:
    在这里插入图片描述

3、第二个版本——定页爬取

由于方法一在网不好的时候会导致请求失败,不可能重新运行该代码,最好的方式就是跟着上面的进程继续往下走,所有必须从上面失败的页数开始爬取。

3.1、分析网页

网页上有快速跳转到某个页面的功能,所有可以利用这个方式进行定页爬取数据,
在这里插入图片描述
操作步骤流程:

  1. 找到该输入框的节点
  2. 输入页数
  3. 点击确定
  4. 点击下一页

所以在我输入的页数就要先减一,回到前一页,然后就可以调用一起的函数,点击下一页回到当前页,获取源代码,继续下一页。。。

3.2、代码汇总

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from lxml import etree
import time,xlwt

startTime =time.time()
all_page = []
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
driver = webdriver.Chrome()
driver.implicitly_wait(5)
chrome_option = webdriver.ChromeOptions()
chrome_option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP
driver.get(url)#打开网页网页
driver.implicitly_wait(6)#等待加载六秒
time.sleep(5)
gotopage = int(input("请输入您开始的页数:"))
gotopage = gotopage-1#减1的目的是前一页,让它点击下一页后才爬取
endpage = int(input("请输入结束的页数:"))

def choose_page():
    search = driver.find_element_by_xpath('//*[@id="gotopage"]')#定位输入框节点
    search.clear()#清空搜索框
    search.send_keys(gotopage)#输入关键词
    driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/input[2]').click()#点击确定
    next_page()

def next_page():
    for page in range(gotopage+1,endpage+1,1):
        print ("~~~~~~~~~~正在爬取第%s页,一共有%s页~~~~~~~~~"%(page,endpage))
        if int(page) == 1:
            get_html()
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()
        
def get_html():
    driver.implicitly_wait(5)
    source = driver.page_source#获取源码
    html = etree.HTML(source)
    spider(html)
        
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')
            price = tr.xpath('./td[3]/span/text()')
            unit = tr.xpath('./td[3]/text()')
            market = tr.xpath('./td[4]/a/text()')
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]                        
            page = [time,goods,price,unit,market,link]#生成数组
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#创建工作簿
    sheet = book.add_sheet('生姜',cell_overwrite_ok=True)#创建表名,cell_overwrite_ok=True用于确认同一个cell单元是否可以重设值
    head = ['时间','产品','价格','单位','市场','链接']#定义表头,即Excel中第一行标题
    for h in range(len(head)):
        sheet.write(0,h,head[h])#写入表头

    j = 1#第一行开始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,并写入数据,重新设置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\农产品(生姜).xls')
    
if __name__ == '__main__':
    choose_page()
    endTime =time.time()
    useTime =(endTime-startTime)/60
    driver.quit()#推出并关闭浏览器
    print ("该次所获的信息一共使用%s分钟"%useTime)

运行结果:
在这里插入图片描述

4、第三个版本——全自动化爬取

由于会弹出浏览器页面,总是会影响我其他的操作,所以我要把浏览器关闭掉,代码在运行的时候,我继续做其他的事,这就面临着这几个问题:

4.1、全自动化三问题

4.1.1、自动点击弹窗

selenium提供switch_to_alert方法:捕获弹出对话框(可以定位alert、confirm、prompt对话框)

switch_to_alert() --定位弹出对话框
text() --获取对话框文本值
accept() --相当于点击“确认”
dismiss() --相当于点击“取消”
send_keys() --输入值(alert和confirm没有输入对话框,所以就不用能用了,只能使用在prompt里)

1、alert窗口处理

# 获取alert对话框
dig_alert = driver.switch_to.alert

# 打印警告对话框内容
print(dig_alert.text)

# alert对话框属于警告对话框,我们这里只能接受弹窗
dig_alert.accept()

2、confirm窗口处理

# 获取confirm对话框
dig_confirm = driver.switch_to.alert

# 打印对话框的内容
print(dig_confirm.text)

# 点击“确认”按钮
dig_confirm.accept()

# 点击“取消”按钮
dig_confirm.dismiss()

3、prompt窗口处理

# 获取prompt对话框
dig_prompt = driver.switch_to.alert

# 打印对话框内容
print(dig_prompt.text)

# 在弹框内输入信息
dig_prompt.send_keys("Loading")

# 点击“确认”按钮,提交输入的内容
dig_prompt.accept()

该网页的弹窗正好符合第一种弹窗,只有确定按钮!

4.1.2、自动输入随机验证码

  • 产生随机4位数的验证码
import random
random.randrange(1000,9999,1)#1000<=随机数<=9999,间隔为1

4.1.3、退出浏览器

  • 由于把浏览器隐藏起来了,所以代码运行完以后需要把浏览器关闭退出
driver.quit()#推出并关闭浏览器

4.2、代码汇总

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from lxml import etree
import time,xlwt,random

startTime =time.time()#获取开始时的时间
all_page = []
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')#上面三行代码就是为了将Chrome不弹出界面,实现无界面爬取
driver = webdriver.Chrome(chrome_options=chrome_options)

option = webdriver.ChromeOptions()
option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP

driver.get(url)#打开网页网页
driver.implicitly_wait(6)#等待加载六秒

alert = driver.switch_to.alert #切换到alert
# print('alert text : ' + alert.text) #打印alert的文本
alert.accept() #点击alert的【确认】按钮

gotopage = int(input("请输入您开始的页数:"))
gotopage = gotopage-1#减1的目的是前一页,让它点击下一页后才爬取
endpage = int(input("请输入结束的页数:"))
randomNumber = random.randrange(1000,9999,1)#随机生成一个四位数的验证码
def choose_page():
    #自动输入验证码
    validity = driver.find_element_by_xpath('//*[@id="formJghqIndex"]/div/input[1]')
    validity.clear()#清空搜索框
    validity.send_keys(randomNumber)#输入随机验证码
    driver.find_element_by_xpath('//*[@id="formJghqIndex"]/div/input[2]').click()
    driver.implicitly_wait(3)#等待加载三秒
    #选择起始页
    search = driver.find_element_by_xpath('//*[@id="gotopage"]')#定位输入框节点
    search.clear()#清空搜索框
    search.send_keys(gotopage)#输入关键词
    driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/input[2]').click()
    time.sleep(4)
    next_page()

#点击下一页
def next_page():
    for page in range(gotopage+1,endpage+1,1):
        print ("~~~~~~~~~~正在爬取第%s页,一共有%s页~~~~~~~~~"%(page,endpage))
        if int(page) == 1:#第一页时直接获取源代码
            get_html()
        #点击下一页
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()

#获取网页源码并解析        
def get_html():
    driver.implicitly_wait(5)
    source = driver.page_source#获取源代码
    html = etree.HTML(source)#使用lxml解析网页
    spider(html)

#提取信息
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')
            price = tr.xpath('./td[3]/span/text()')
            unit = tr.xpath('./td[3]/text()')
            market = tr.xpath('./td[4]/a/text()')
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]                        
            page = [time,goods,price,unit,market,link]#生成数组
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#创建工作簿
    sheet = book.add_sheet('生姜',cell_overwrite_ok=True)#创建表名,cell_overwrite_ok=True用于确认同一个cell单元是否可以重设值
    head = ['时间','产品','价格','单位','市场','链接']#定义表头,即Excel中第一行标题
    for h in range(len(head)):
        sheet.write(0,h,head[h])#写入表头

    j = 1#第一行开始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,并写入数据,重新设置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\农产品(生姜).xls')
    
if __name__ == '__main__':
    choose_page()
    endTime =time.time()#获取结束时的时间
    useTime =(endTime-startTime)/60
    driver.quit()#推出并关闭浏览器
    print ("该次所获的信息一共使用%s分钟"%useTime)

编辑器运行结果:
在这里插入图片描述
Excel结果截屏:
在这里插入图片描述

发布了62 篇原创文章 · 获赞 25 · 访问量 9305

猜你喜欢

转载自blog.csdn.net/ayouleyang/article/details/103844538