常见的反爬机制及处理方式
1、Headers反爬虫 :Cookie、Referer、User-Agent
解决方案: 通过F12获取headers,传给requests.get()方法
2、IP限制 :网站根据IP地址访问频率进行反爬,短时间内进制IP访问
解决方案:
1、构造自己IP代理池,每次访问随机选择代理,经常更新代理池
2、购买开放代理或私密代理IP
3、降低爬取的速度
3、User-Agent限制 :类似于IP限制
解决方案: 构造自己的User-Agent池,每次访问随机选择
5、对查询参数或Form表单数据认证(salt、sign)
解决方案: 找到JS文件,分析JS处理方法,用Python按同样方式处理
6、对响应内容做处理
解决方案: 打印并查看响应内容,用xpath或正则做处理
python中正则处理headers和formdata
1、pycharm进入方法 :Ctrl + r ,选中 Regex
2、处理headers和formdata
(.*): (.*)
"1":"1":"2",
3、点击 Replace All
民政部网站数据抓取
目标: 抓取最新中华人民共和国县以上行政区划代码
URL: http://www.mca.gov.cn/article/sj/xzqh/2019/ - 民政数据 - 行政区划代码
实现步骤
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、在数据库表中查询此条链接是否已经爬取,建立增量爬虫
数据库中建立version表,存储爬取的链接
每次执行程序和version表中记录核对,查看是否已经爬取过
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('M%%%M4(vrv %r>`rv>.4(輽йэ %%4(Z4(鉅4)}(5饱]9P]=\]-м-!Q50
M4(5饱]9P]=\4(5饱иM%9P]=\миM1
9P
1H9P
1H9P
1H5
A9PиA4)t4(4)4)4)4))}4)QФ}}|}輽йэE%%%%%M4(}輽йэ %%4(й&O(}cR>[j_64(:>[N74(UМ}С(_V6z,4(4(胢:>[&r'V64(}}}4(4(lфulAtltlI9tB7(}lA%t%.vrv 4(.rv :>[3J34(}}С}4(llt}}}4(С4(}*""_(zCv4(}}}}4(lфulIt(qq:'604(lфulIНt4(qq:'604(4(:>[V(}Р4(4(Сlфul
Нt?r$:6@4(4(4(}}С4(}}4("rrZ(}}4(4)}}}|}}}|4(4(4(4(Р&3^^4(brZj3ro疒j惚r'&*rokkR2 |