爬取ajax数据的两种方式
- 分析接口
- 使用selenium
释义
:1.在不重载整个网页界面的情况下,新增数据展示。2.在浏览器中 查看网页源代码,不能看到ajax加载的数据(举个例子,点击加载更多,还是还是不能再网页源代码中查看到数据)
selenium
Selenium是一个用于Web应用程序测试的工具。主要解决javascript渲染的问题
Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。
支持的浏览器包括IE,Mozilla和Firefox等。
这个工具的主要功能包括:测试与浏览器的兼容性,测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能,创建衰退测试检验软件功能和用户需求。
chromedirver操作网页
chromedirver下载对应版本到python 安装目下的scrprts中
云盘下载,提取码:a1wd
简单测试
from selenium import webdriver
borswer = webdriver.Chrome()
就能打开一个google浏览器了。
selenium详解
参考资料-selenium详解
定位元素
from selenium import webdriver
import time
from lxml import etree
broswer=webdriver.Chrome()
broswer.get("https://www.baidu.com/")
# time.sleep(5)
# broswer.close()
#inputTag=broswer.find_element_by_id('kw')
#inputTag=broswer.find_element_by_class_name('s_ipt')
#inputTag=broswer.find_element_by_xpath('//input[@class="s_ipt"]')
#inputTag=broswer.find_element_by_css_selector('#kw') #浏览器copy,选择selector生成
# inputTag=broswer.find_element_by_xpath('//*[@id="kw"]')#浏览器copy,选择xpath生成,需加//
# inputTag.send_keys("python")
#为了快速解析数据,推荐lxml拉埃解析,底层c语言,解析小兰高,
#如果是对元素进行操作,插入输入值等,就必须使用selenium的方法了
html=etree.HTML(broswer.page_source)
btn_text=html.xpath("//input[@id='su']/@value")[0]
print(btn_text)
操作表单元素
常见的input type='text/password/eamil/num'
input type='submit'
intput type='checkbox',
- 填入数据 send_keys("")
- 清除数据 clear()
- click()点击
- select元素不能点击,一般包装一个Select()
from selenium.webdriver.support.select import Select
...
#包装
selectTag=Select(broswer.find_element_by_class_name("XXX"))
#根据索引
selectTag.select_by_index("XX")
#根据值
selectTag.select_by_value("XXX")
#根据文字
selectTag.select_by_visible_text("XXX")
#取消所有选项
selectTag.deselect_all()
行为链接
有时候在页面的操作有很多步,这时可使用行为链,ActionChans来完成
举个例子:
百度界面,输入python,点击按钮进行搜索。一般方式如下
inputTag=broswer.find_element_by_xpath('//*[@id="kw"]')#浏览器copy,选择xpath生成,需加//
inputTag.send_keys("python")
btnTag=broswer.find_element_by_xpath("//input[@id='su']")
btnTag.click()
采用行为链
的方式
inputTag=broswer.find_element_by_xpath('//*[@id="kw"]')#浏览器copy,选择xpath生成,需加//
btnTag=broswer.find_element_by_xpath("//input[@id='su']")
actions=ActionChains(broswer)
#移动到输入框中上
actions.move_to_element(inputTag)
#进行输入值
actions.send_keys_to_element(inputTag,"Python书籍")
#移动到搜索按钮上
actions.move_to_element(btnTag)
#点击搜索按钮
actions.click(btnTag)
#确认
actions.perform()
其他鼠标相关操作
- click_and_hold(e):点击但不松开鼠标
- content_click(e):右击鼠标
- double_click(e):双击
更多参考官网
cookie操作
- 获取所有的cookie
x.get_cookies() - 根据cookie的key获取value
x.get_cookie(key) - 删除所有cookie
delete_all_cookies() - 删除某个cookie
x.delete_cookie(key)
页面等待
不确定某个原始何时加载出来
- 隐式等待
broswer.implicitly_wait(10)
- 显示等待
ele = WebDriverWait(broswer, 10).until(EC.presence_of_element_located(By.CSS_SELECTOR, "#kw"))
ele.send_keys("python")
切换页面
有时候窗口中有很多的子tab页面,这时候是需要进行切换的,switch_to.winow
来进行切换,具体切换都哪个界面,可以从driver.window_handles
中找到
broswer.get("https://www.baidu.com/")
broswer.execute_script("window.open('https://www.douban.com/')")
print(broswer.current_url)#当前还是baidu
broswer.switch_to.window(broswer.window_handles[1])
print(broswer.current_url)#当前是douban
使用代理
网页查看ip的网址http://httpbin.org/ip
options=webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://61.189.242.243:55484")
broswer = webdriver.Chrome(chrome_options=options)
broswer.get("http://httpbin.org/ip")
补充 webelement
获取属性,保存图片等
broswer = webdriver.Chrome()
broswer.get("http://www.baidu.com")
btn=broswer.find_element_by_id("su")
print(btn.get_attribute("value"))
broswer.save_screenshot("baidu.jpg")
实战 爬取拉钩网
拉勾网典型的使用ajax技术网站
https://www.lagou.com/jobs/list_python?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput=
一,分析接口,使用requests来请求
问题:
需要加
Referer
,这是拉钩设置的反扒机制,如果爬取其他网站过程中,还是获取不到数据,就把headers中的都添加进去。
import requests
from lxml import etree
def get_page():
url="https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false"
proxy = {
'http': '180.110.7.234:3128'
}
head={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Referer":"https://www.lagou.com/jobs/list_python?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput="}
data ={
'first':"false",
'pn':1,
'kd':'python'
}
response=requests.post(url,headers=head,data=data,proxies=proxy)
print(response.json())
def main():
get_page()
if __name__ == '__main__':
main()
这样子就能拿到返回的json数据啦,就可以自己取数据啦。
for x in range(1, 10):
time.sleep(2)
response=requests.post(url,headers=head,data=data,proxies=proxy)
print(response.json())
注意在循环遍历爬取的时候,又被反扒了
,加了头部信息。才又成功。
使用代理,可以解决问题
获取详情,全部代码参考
import requests
from lxml import etree
import time
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Referer": "https://www.lagou.com/jobs/list_python?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput=",
"Origin": "https://www.lagou.com",
}
def get_page_url():
url = "https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false"
data = {
'first': "false",
'pn': 1,
'kd': 'python'
}
for x in range(1, 2):
data['pn'] = x
response = requests.post(url, headers=head, data=data)
try:
result = response.json()
postions = result["content"]["positionResult"]['result']
#数量太多,最后延时,
for pos in postions:
postion_id = pos["positionId"]
pos_url = "https://www.lagou.com/jobs/{}.html".format(postion_id)
parse_p_details(pos_url)
break
except Exception as e:
print(e.args)
def parse_p_details(url):
response=requests.get(url,headers=head)
htmlEle=etree.HTML(response.text)
compony=htmlEle.xpath("//*[@id='job_company']/dt/a/div/h2/text()")[0]#使用浏览器一键复制的
xinshui=htmlEle.xpath("/html/body/div[3]/div/div[1]/dd/p[1]/span[1]/text()")[0]#使用浏览器一键复制的
desc="\n".join(htmlEle.xpath("//dd[@class='job_bt']//p/text()"))#自己判断的,获取该类下的所有段落的文本
print(desc)
def main():
get_page_url()
if __name__ == '__main__':
main()
最佳方式使用 seleinum
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from lxml import etree
"""
流程:1.打开当前页,获取每个链接。循环获取每个链接中的详情内容
2.完毕之后,点击下一页,重复1
"""
class LanGou(object):
def __init__(self):
self.marks=[]
self.broswer=webdriver.Chrome()
self.broswer.implicitly_wait(20)
#该地址就是网址实际地址,不用在network寻找
self.url="https://www.lagou.com/jobs/list_python?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput="
def run(self):
#循环遍历每一页,最好睡几秒
self.broswer.get(self.url)
while True:
#page_source相当于源代码啦
source=self.broswer.page_source
# WebDriverWait(driver=self.broswer, timeout=10).until(
# EC.presence_of_element_located((By.XPATH, "//div[@class='pager_container']/span[last()]")))
#self.parse_one_page(source)
#上面是爬取完一页
#进行下一页,翻页
#第三部,请求完第一页,进入第二页,知道不能点击
next_page_btn =self.broswer.find_element_by_xpath("//div[@class='pager_container']/span[last()]")
if "pager_next_disabled" in next_page_btn.get_attribute("class"):
break
else:
print("page")
next_page_btn.click()
time.sleep(2)
#第一步,请求界面,
def parse_one_page(self,sourse):
htmlEle=etree.HTML(sourse)
#1页有多少个职位就有好多连接
links=htmlEle.xpath("//a[@class='position_link']/@href")
for detail_url in links:
self.request_detail(detail_url)
time.sleep(2)
#第二步,循环请求详情界面数据,窗口切换,关闭,切换到列表页
def request_detail(self,url):
#需要打开新的界面,在详情页中没有下一页按钮
#self.broswer.get(url=url)
self.broswer.execute_script("window.open('{}')".format(url))
self.broswer.switch_to.window(self.broswer.window_handles[1])
source=self.broswer.page_source
self.parse_detail(source)
#关闭当前详情页面,切换到列表页
self.broswer.close()
self.broswer.switch_to.window(self.broswer.window_handles[0])
#注意L使用显示等待,xpath解析,不需要写最后的text(),是获取不到的,一般解析需要text()
def parse_detail(self,source):
htmlEle = etree.HTML(source)
compony = htmlEle.xpath("//dl[@class='job_company']/dt//h2/text()")[0].strip()
xinshui = htmlEle.xpath("//span[@class='salary']/text()")[0]
desc = "\n".join(htmlEle.xpath("//dd[@class='job_bt']//p/text()")) # 获取该类下的所有段落的文本
mark = {
'compony': compony.strip(),
'xinshui': xinshui.strip(),
'desc': desc
}
self.marks.append(mark)
print("*" * 20)
print(mark)
if __name__ == '__main__':
spider=LanGou()
spider.run()
注意
:重复在第二页,原因把get(url)放在了While True中,导致每次要刷新,所以在1,2,页切换