ajax抓取网页内容( 2019年X月中华人民共和国县以上反爬机制及处理方式)

优采云 发布时间: 2021-09-16 04:09

  ajax抓取网页内容(

2019年X月中华人民共和国县以上反爬机制及处理方式)

  Python抓取Ajax动态加载网页分析

  更新时间:2019年9月5日08:47:06作者:凌妮珊

  本文文章主要介绍Python抓取Ajax动态加载网页的过程。通过实例代码对其进行了详细的介绍,对大家的学习或工作有一定的参考价值。有需要的朋友可以参考

  常见防爬机理及处理方法

  1、Headers反爬虫:cookie、referer、用户代理

  解决方案:通过F12获取标题并将其传递给请求。Get()方法

  2、IP限制:网站根据IP地址访问频率进行反向爬网,短时间访问IP

  解决方案:

  1、构建自己的IP代理池,每次访问时随机选择代理,并经常更新代理池

  2、购买开放代理或专用代理IP

  3、降低爬行速度

  3、User-代理限制:类似于IP限制

  解决方案:构建自己的用户代理池,并在每次访问时随机选择它

  5、authenticate查询参数或表单数据(salt、sign)

  解决方案:找到JS文件,分析JS处理方法,并使用Python以相同的方式进行处理

  6、处理响应内容

  解决方案:打印和查看响应内容,并使用XPath或正则表达式进行处理

  Python中标题和表单数据的常规处理

  1、pycharm输入方式:Ctrl+R,选择正则表达式

  2、处理标题和表单数据

  (**):(**)

  “1”:“1”:“2”

  3、单击“全部替换”

  民政部网站数据采集

  目的:获取最新的中华人民共和国县级以上行政区划代码

  URL:-民政数据-行政区划代码

  实施步骤

  1、从民政数据中提取最新的行政区划代码链接网站

  最新的一个在上面。命名格式:2019年x月中华人民共和国县级以上行政区划代码

  

import requests

from lxml import etree

import re

url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'}

html = requests.get(url, headers=headers).text

parse_html = etree.HTML(html)

article_list = parse_html.xpath('//a[@class="artitlelist"]')

for article in article_list:

title = article.xpath('./@title')[0]

# 正则匹配title中包含这个字符串的链接

if title.endswith('代码'):

# 获取到第1个就停止即可,第1个永远是最新的链接

two_link = 'http://www.mca.gov.cn' + article.xpath('./@href')[0]

print(two_link)

break

  2、从第二页链接中提取真实链接(反爬网响应,在网页内容中嵌入JS,并指向新的网页链接)

  向辅助页面链接发送请求以获取响应内容,并查看嵌入的JS代码

  真实二级页面链接的常规提取

  

# 爬取二级“假”链接

two_html = requests.get(two_link, headers=headers).text

# 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址)

new_two_link = re.findall(r'window.location.href="(.*?)" rel="external nofollow" rel="external nofollow" ', two_html, re.S)[0]

  3、query是否已在数据库表中对此链接进行爬网,以建立增量爬网器

  在数据库中构建版本表以存储爬网链接

  每次执行程序时,检查版本表中的记录,查看它们是否已被爬网

  

cursor.execute('select * from version')

result = self.cursor.fetchall()

if result:

if result[-1][0] == two_link:

print('已是最新')

else:

# 有更新,开始抓取

# 将链接再重新插入version表记录

  4、代码实现

  

import requests

from lxml import etree

import re

import pymysql

class GovementSpider(object):

def __init__(self):

self.url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'

self.headers = {'User-Agent': 'Mozilla/5.0'}

# 创建2个对象

self.db = pymysql.connect('127.0.0.1', 'root', '123456', 'govdb', charset='utf8')

self.cursor = self.db.cursor()

# 获取假链接

def get_false_link(self):

html = requests.get(url=self.url, headers=self.headers).text

# 此处隐藏了真实的二级页面的url链接,真实的在假的响应网页中,通过js脚本生成,

# 假的链接在网页中可以访问,但是爬取到的内容却不是我们想要的

parse_html = etree.HTML(html)

a_list = parse_html.xpath('//a[@class="artitlelist"]')

for a in a_list:

# get()方法:获取某个属性的值

title = a.get('title')

if title.endswith('代码'):

# 获取到第1个就停止即可,第1个永远是最新的链接

false_link = 'http://www.mca.gov.cn' + a.get('href')

print("二级“假”链接的网址为", false_link)

break

# 提取真链接

self.incr_spider(false_link)

# 增量爬取函数

def incr_spider(self, false_link):

self.cursor.execute('select url from version where url=%s', [false_link])

# fetchall: (('http://xxxx.html',),)

result = self.cursor.fetchall()

# not result:代表数据库version表中无数据

if not result:

self.get_true_link(false_link)

# 可选操作: 数据库version表中只保留最新1条数据

self.cursor.execute("delete from version")

# 把爬取后的url插入到version表中

self.cursor.execute('insert into version values(%s)', [false_link])

self.db.commit()

else:

print('数据已是最新,无须爬取')

# 获取真链接

def get_true_link(self, false_link):

# 先获取假链接的响应,然后根据响应获取真链接

html = requests.get(url=false_link, headers=self.headers).text

# 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址)

re_bds = r'window.location.href="(.*?)" rel="external nofollow" rel="external nofollow" '

pattern = re.compile(re_bds, re.S)

true_link = pattern.findall(html)[0]

self.save_data(true_link) # 提取真链接的数据

# 用xpath直接提取数据

def save_data(self, true_link):

html = requests.get(url=true_link, headers=self.headers).text

# 基准xpath,提取每个信息的节点列表对象

parse_html = etree.HTML(html)

tr_list = parse_html.xpath('//tr[@height="19"]')

for tr in tr_list:

code = tr.xpath('./td[2]/text()')[0].strip() # 行政区划代码

name = tr.xpath('./td[3]/text()')[0].strip() # 单位名称

print(name, code)

# 主函数

def main(self):

self.get_false_link()

if __name__ == '__main__':

spider = GovementSpider()

spider.main()

  动态加载数据抓取Ajax

  特征

  右键单击->查看网页。源代码中没有特定的数据

  滚动鼠标滚轮或其他操作时加载

  ץȡ

  F12打开控制台,选择XHR异步加载数据包,找到页面操作并抓取网络数据包

  通过XHR-->头-->常规-->请求URL获取JSON文件URL地址

  通过XHR-->标题-->查询字符串参数

  豆瓣电影数据采集案例

  目标

  地址:豆瓣电影-排行榜-剧情

  类型名称=%E5%89%A7%E6%83%85&type=11&interval\id=100:90&action=

  目标:提升电影名称和分数

  F12数据包捕获(XHR)

  1、RequestURL(基本URL地址):

  2、Query字符串参数(查询参数)

  

# 查询参数如下:

type: 13 # 电影类型

interval_id: 100:90

action: '[{},{},{}]'

start: 0 # 每次加载电影的起始索引值

limit: 20 # 每次加载的电影数量

  JSON文件位于以下地址:

  参考URL地址+查询参数

  ''+'类型=11,间隔=100%3A90,动作=20,开始=20,限制=20'

  代码实现

  

import requests

import time

from fake_useragent import UserAgent

class DoubanSpider(object):

def __init__(self):

self.base_url = 'https://movie.douban.com/j/chart/top_list?'

self.i = 0

def get_html(self, params):

headers = {'User-Agent': UserAgent().random}

res = requests.get(url=self.base_url, params=params, headers=headers)

res.encoding = 'utf-8'

html = res.json() # 将json格式的字符串转为python数据类型

self.parse_html(html) # 直接调用解析函数

def parse_html(self, html):

# html: [{电影1信息},{电影2信息},{}]

item = {}

for one in html:

item['name'] = one['title'] # 电影名

item['score'] = one['score'] # 评分

item['time'] = one['release_date'] # 打印测试

# 打印显示

print(item)

self.i += 1

# 获取电影总数

def get_total(self, typ):

# 异步动态加载的数据 都可以在XHR数据抓包

url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(typ)

ua = UserAgent()

html = requests.get(url=url, headers={'User-Agent': ua.random}).json()

total = html['total']

return total

def main(self):

typ = input('请输入电影类型(剧情|喜剧|动作):')

typ_dict = {'剧情': '11', '喜剧': '24', '动作': '5'}

typ = typ_dict[typ]

total = self.get_total(typ) # 获取该类型电影总数量

for page in range(0, int(total), 20):

params = {

'type': typ,

'interval_id': '100:90',

'action': '',

'start': str(page),

'limit': '20'}

self.get_html(params)

time.sleep(1)

print('爬取的电影的数量:', self.i)

if __name__ == '__main__':

spider = DoubanSpider()

spider.main()

  腾讯招聘数据采集(Ajax)

  确定URL地址和目的地

  网址:百度搜索腾讯招聘-查看职位

  目标:职位名称、工作职责和工作要求

  需求与分析

  通过查看web源代码,我们知道所需的数据是Ajax动态加载

  通过F12抓取网络数据包进行分析

  第一级页面捕获数据:职位名称

  第二页捕获的数据:工作职责和工作要求

  第一级页面JSON地址(页面索引正在更改,未检查时间戳)

  {}&pageSize=10&language=zh-cn&area=cn

  辅助页面地址(postid正在更改,可以在主页面中获取)

  {}&language=zh cn

  Useragents.py文件

  

ua_list = [

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',

'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',

'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)',

]

  

import time

import json

import random

import requests

from useragents import ua_list

class TencentSpider(object):

def __init__(self):

self.one_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1563912271089&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn'

self.two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1563912374645&postId={}&language=zh-cn'

self.f = open('tencent.json', 'a') # 打开文件

self.item_list = [] # 存放抓取的item字典数据

# 获取响应内容函数

def get_page(self, url):

headers = {'User-Agent': random.choice(ua_list)}

html = requests.get(url=url, headers=headers).text

html = json.loads(html) # json格式字符串转为Python数据类型

return html

# 主线函数: 获取所有数据

def parse_page(self, one_url):

html = self.get_page(one_url)

item = {}

for job in html['Data']['Posts']:

item['name'] = job['RecruitPostName'] # 名称

post_id = job['PostId'] # postId,拿postid为了拼接二级页面地址

# 拼接二级地址,获取职责和要求

two_url = self.two_url.format(post_id)

item['duty'], item['require'] = self.parse_two_page(two_url)

print(item)

self.item_list.append(item) # 添加到大列表中

# 解析二级页面函数

def parse_two_page(self, two_url):

html = self.get_page(two_url)

duty = html['Data']['Responsibility'] # 工作责任

duty = duty.replace('\r\n', '').replace('\n', '') # 去掉换行

require = html['Data']['Requirement'] # 工作要求

require = require.replace('\r\n', '').replace('\n', '') # 去掉换行

return duty, require

# 获取总页数

def get_numbers(self):

url = self.one_url.format(1)

html = self.get_page(url)

numbers = int(html['Data']['Count']) // 10 + 1 # 每页有10个推荐

return numbers

def main(self):

number = self.get_numbers()

for page in range(1, 3):

one_url = self.one_url.format(page)

self.parse_page(one_url)

# 保存到本地json文件:json.dump

json.dump(self.item_list, self.f, ensure_ascii=False)

self.f.close()

if __name__ == '__main__':

start = time.time()

spider = TencentSpider()

spider.main()

end = time.time()

print('执行时间:%.2f' % (end - start))

  以上是本文的全部内容。我希望这将有助于你的学习,我希望你能支持脚本的房子

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线