协程用的不多,但是也是实现并发的一种方式,协程的特点是,在执行的过程中,如果遇到需要等待的时候,会自动切换到另外
一个协程中执行,本次是用协程的特点,实现一个并发的爬虫。
首先,创建一个协程执行的函数,如:
函数参数的含义:
url : 爬取的网站连接
start:爬取的起始页(每个协程中爬取的起始页都不相同)
end:爬取的终止也页(同上)
file:爬取的数据存储的文件
在主函数(main)中创建五个协程:
HandleAll是每个协程执行的函数,也是本次爬虫的主要部分,该函数包括url的处理,数据的提取,第二和第三个参数是每个协
程负责爬取的页数范围。
整体的程序如下:
from selenium import webdriver from bs4 import BeautifulSoup #导入协程相关的库 import gevent def HandleAll(url,start,end,file): #每个协程指定的下载页数的范围 for i in range(start,end): driver = webdriver.Chrome() if i == 0: theurl = url else: theurl = url + "&page=" + str(i*2-1) print("第%s页在下载"%(i+1)) print(theurl) driver.get(theurl) """ 该语句的作用是在浏览器加载完页面后,把页面拉到底部 因为京东是下拉加载的 """ driver.execute_script("window.scrollTo(0,document.body.scrollHeight)") """ 这里一定要写成gevent.sleep(),如果写成time.sleep() 则会失去协程的作用 当执行到gevent.sleep()时,协程会自动切换到另外一个协程进行执行 切换的顺序是按照主函数中的gevent.joinall的顺序 当切换到最后一个协程同时执行到这里的时候,就会返回第一个协程,然后是第二个协程 依次类推 """ gevent.sleep(5) body = driver.page_source driver.close() #以下是用BeautifulSoup对页面进行提取 soup = BeautifulSoup(body,"lxml") lilsit = soup.select(".gl-item") for li in lilsit: name = li.select(".p-name")[0].get_text() store = li.select(".J_im_icon") if store: store = store[0].get_text() else: store = "" price = li.select(".p-price")[0].get_text() discount = li.select(".p-icons")[0].get_text() url = li.select(".p-img")[0].select('a')[0]['href'] if url[:5] == "https": pass else: url = "https:" + url try: imgurl = li.select('.err-product')[0]['src'] if imgurl[:5] == "https": pass else: imgurl = "https:" + imgurl except: imgurl = '' print(imgurl) data = " # ".join([name,store,price,discount,url,imgurl]) data += "\r\n" file.write(data.encode("utf-8")) if __name__ == '__main__': url = "https://search.jd.com/Search?keyword=%E5%A5%B3%E8%A3%85%E5%A4%8F%E5%AD%A3%E8%A3%99%E5%AD%90&enc=utf-8" file = open("save.txt",'wb') #创建五个协程 gevent.joinall([ gevent.spawn(HandleAll, url, 0, 5, file), gevent.spawn(HandleAll, url, 5, 10, file), gevent.spawn(HandleAll, url, 10, 15, file), gevent.spawn(HandleAll, url, 15, 20, file), gevent.spawn(HandleAll, url, 20, 25, file), ]) file.close()