对于有规律的Ajax请求,我们可以分析它的特点,从而抓取一个又一个的Ajax去获取请求,但,有些网站为了反爬,它的Ajax是没有规律的,我们举个例子,拉勾网
我们进入拉勾网,搜索python,检查,切换到network,过滤请求,这里只要Ajax请求,下滑到底部,点击下一页:
图中标有1,2的两个请求,就是包含职位信息的Ajax请求,分别是第一页的和第二页的,我们可以发现,两个Request URL是一样的,也就是说,这里并没有参数让我们区分不同的Ajax请求有什么区别,而且,如果你访问这个Ajax,即使是浏览器也会这样:
更不用说爬虫了。
那针对这样的网站,我们怎么能获取大量数据呢。
我们这次的目的是,爬取详细信息,多页。我们需要,selenium,chromedriver,lxml,MongoDB
先上代码
from selenium import webdriver
from lxml import etree
import time
from pymongo import MongoClient
client = MongoClient()
db = client['LaGou']
collection = db['lagou_position']
#写入chromedriver路径
driver_path = r"D:\pythontools\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
def parse_page(url):
driver.get(url)
while True:
resp = driver.page_source
# print(resp)
text = etree.HTML(resp)
position_links = text.xpath("//a[@class='position_link']/@href")
next_btn = driver.find_element_by_class_name("pager_next ")
# next_btn.click()
for position_link in position_links:
# print(position_link)
parse_detail_page(position_link)
if "pager_next pager_next_disabled" in next_btn.get_attribute("class"):
break
else:
next_btn.click()
time.sleep(1)
def parse_detail_page(position_link):
position = {}
driver.execute_script("window.open('%s')"%position_link)
driver.switch_to.window(driver.window_handles[1])
resp = driver.page_source
text = etree.HTML(resp)
position_name = text.xpath("//span[@class='name']/text()")[0]
position_producer = text.xpath("//span[@class='name']/text()")[1]
position_salary = text.xpath("//dd[@class='job_request']//span/text()")[0]
position_city = text.xpath("//dd[@class='job_request']//span/text()")[1]
position_undergo = text.xpath("//dd[@class='job_request']//span/text()")[2]
position_edu = text.xpath("//dd[@class='job_request']//span/text()")[3]
position_detail = text.xpath("//div[@class='job-detail']//p/text()")
# print(position_detail)
# print(position_salary,position_city,position_undergo,position_edu)
# print(position_salary)
# print(position_name)
# print(position_producer)
position["职位名称"] = position_name
position["发布者"] = position_producer
position["薪资"] = position_salary
position["城市"] = position_city
position["经验要求"] = position_undergo
position["学历背景"] = position_edu
position["职位描述"] = position_detail
save_to_mongo(position)
driver.close()
driver.switch_to.window(driver.window_handles[0])
def save_to_mongo(position):
if collection.insert(position):
print("Sava is ok!")
def main():
url = "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput="
parse_page(url)
if __name__ == '__main__':
main()
注释内容为测试数据。仅参考。
我们来分析代码实现原理。
我们依旧用了一个main函数来传主页url,需要注意到,你点击下一页是,网页链接并不会变化,只是在用Ajax请求进行数据交互
是不随你改变页面而改变的。
我们定义了一个parse_page,处理第一页第二页这样的页面,提取详细职位的href属性,让parse_detail_page去点击,模拟浏览器进入到详情页,我们还获取了下一页的按钮,如果有下一页就点击,没有就退出:
if "pager_next pager_next_disabled" in next_btn.get_attribute("class"): break else: next_btn.click()
我们应该注意到,最后一页的next_btn的class属性和其他是不一样的。
我们再看parse_detail_page,它用来处理详情页,我们要注意,我们要在新窗口打开,不能直接get打开,否则覆盖了主页,就无法进行翻页点击。
然后通过窗口下标去切换到详情页。
存储信息进mongo后,关闭窗口,切换回主页。
代码运行的时候,可以看见浏览器一直在切换和翻页。
我们看下数据库,我的compass安装好了,另外,备注一下compass的一个特点吧,
一:先打开mongo才能连接。
二:如果你打开了mongo,在打开compass,完成需要工作后,关闭compass,再次点击compass会error:
像这样,原因是,直接关闭对compass是没用的,你需要ctrl+shift+esc找到compass,结束进程在启动即可。