为什么使用selenium
在前面的文章中,我们了解了Ajax的分析和爬取方式,但是,对于参数加密复杂的网页来说,用之前构造请求头的方法来爬取数据未免显得困难,所以这里我们选择了使用selenium。
Selenium是一个自动化测试工具,通过它我们可以驱动浏览器执行特定的动作,对于一些参数加密复杂的javaScript渲染的页面来说,抓取效果很好。采用selenium,我们可以做到可见即可爬的效果。
selenium安装(不详细介绍,只介绍步骤)
- 这里我们直接采用pip来安装selenium: pip install selenium
- 安装Chrome以及ChromeDriver驱动:这里选择的chrome的版本需要与ChromeDriver匹配
- 下载好后,将ChromeDriver的可执行文件配置到环境变量中
- 验证安装:
- 上面的步骤配置完成后,在终端命令行下输入Chromedriver,输出Strating.........Only local connections are allowed,即安装成功
- 或者创建如下python代码:
from selenium import webdriver
browser=webdriver.Chrome()
运行之后,弹出一个空白的Chrome浏览器,则证明安装成功。
爬取马蜂窝地区全部景点代码
- 对于selenium的一些基本知识,可以自行到selenium中文文档中学习,内容简短,充分提升自己的个人学习能力。
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from pyquery import PyQuery as pq
import time
import os
import urllib
browser=webdriver.Chrome()
wait=WebDriverWait(browser,10)
url='http://www.mafengwo.cn/jd/10206/gonglve.html'
browser.get(url)
aomeng={}
def index_page():
try:
#获取总页数
page_total=browser.find_elements_by_css_selector('span.count')
total=page_total[0].text
total_page=total[1:3]
for i in range(1,int(total_page)-4):
print('正在爬取第',str(i),'页')
#实现下一页
submit=wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.m-pagination > a.pi.pg-next')))
submit.click()
html=browser.page_source
parse_page(html)
#print(html)
except TimeoutException:
print('超时')
finally:
browser.close()
def parse_page(html):
doc=pq(html,parser="html")
items=doc('.bd .scenic-list.clearfix .img').parent().items()
for item in items:
#标题
aomeng['title']=item.find('h3').text()
#子页链接
aomeng['href']=item.attr('href')
#图片链接
aomeng['img']=item.find('.img').find('img').attr('src')
time.sleep(3)
save_img(aomeng)
def save_img(aomeng):
if not os.path.exists(aomeng['title']):
os.makedirs(aomeng['title'])
with open('{0}/{0}.{1}'.format(aomeng['title'], 'txt'), 'a',encoding='utf-8')as f:
f.write(aomeng['href'])
print('写入txt文件成功')
try:
file_path = '{0}/{0}.{1}'.format(aomeng['title'], 'jpg')
if not os.path.exists(file_path):
urllib.request.urlretrieve(aomeng['img'], file_path)
print('img 存入success!')
else:
print('Already Download')
except :
print('img 存入fail!')
pass
index_page()
运行结果:
2.也可以采用之前构造参数的方式爬取(这里引用公众号: Python绿色通道 的方法):这里我们只介绍获取数据页代码,具体的解析,自行根据需要解析:
先抓包,在xhr中点击一次下一页,就有生成三个页面。其中所需要的内容在router.php中。
找到这个js文件http://js.mafengwo.net/js/hotel/sign/index.js?1552035728。在第363行和第364行打上断点,然后点击下一页。
第363行会生成一个json变量 _0xe7fex39。在第364行,首先运行这一部分:(JSON[__Ox2133f[60]](_0xe7fex39) + _0xe7fex34)即生成一个字符串类型的变量:"{"_ts":"1553500557401","params":"{\"poi_id\":\"87950\",
\"page\":1,\"just_comment\":1}"}c9d6618dbc657b41a66eb0af952906f1"
然后再通过函数_0xe7fex2生成32位的字符串;最通过slice(2,12)函数对其进行切割,获得2-12的字符串,这个就是_sn的值。
查找这个函数发现_0xe7fec函数将变量生成一个长度为4的数组;在通过_0xe7fex10函数将数组生成对应的字符串;最后将_0xe7fex15拼接起来。
而拼接后的这串字符的2-12位就是_sn值。这整个加密过程就是常说的md5加密。右边的加密结果和_0xe7fex15拼接起来的字符串是完全一样的;
此时生成的_sn值bc28b3ed57就是对参数进行md5加密取2-12位的结果。
得到_sn值后,评论数据就可以很容易就得到。这里要注意的是,在请求是必须把url拼接完整,否则只会返回一点点数据。另外在生成_sn时,参数qdata必须保持一致,是双引号就是双引号,有反斜杠就要有反斜杠,不然得不到正确的_sn值。
代码:
import hashlib
import requests
#可将t改为你想爬取的地区参数
t=1556449494051
def par(t):
hl = hashlib.md5()
hl.update(t)
return hl.hexdigest()[2:12]
def get_page():
for i in range(19):
print('第'+str(i)+'页')
page=str(i)
#可将iMddid改为你想爬取的地区码
qdata = '{"_ts":"' + str(t) + '","iMddid":"10206","iPage":"' + str(
page) + '","iTagId":"0","sAct":"KMdd_StructWebAjax|GetPoisByTag"}c9d6618dbc657b41a66eb0af952906f1'
sn = par(qdata.encode('utf-8'))
url = "http://www.mafengwo.cn/ajax/router.php"
data = {
'sAct': 'KMdd_StructWebAjax|GetPoisByTag',
#可将iMddid改为你想爬取的地区码
'iMddid': '10206',
'_ts': t,
'iPage': page,
'iTagId': '0',
'_sn': sn
}
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
response = requests.request("POST", url, headers=headers,data=data)
print(response.text)
get_page()