python笔记之爬虫笔记(一)——自建小型ip池以及mysql数据库的简单运用

前言

最近在爬取知乎的资料时,无奈在测试的时候一直频繁访问,导致IP被封(被封的提示为:ip地址被封))于是在多次提取无果以后,如果购买代理不划算啊,刚好最近学了mysql数据库,为何不自建一个小型的ip代理池呢,顺便做个小项目练练手,供个人获取数据应该是够了,自力更生,丰衣足食。废话就不说了,

直接上正文

一、寻找代理网站提供的几十个免费代理 。像西刺代理,百度一抓一大把,一般选择一个就行了,选择一个合适的start_url地址就可以了
二.发送请求,并获取element 类型的html,方便使用xpath提取(直接看代码)

def parse_url(self,url):
        '''一个发送请求,获取响应,同时etree处理html'''
        response = requests.get(url,headers=self.headers,timeout=10) #发送请求
        html = response.content.decode() #获取html字符串  为什么不能直接html = response.text 一样得到的是html字符串啊?
        html_etree = etree.HTML(html) #获取element 类型的html
        return html_etree

三.提取数据(提取如123.161.160.74:8080形式的good_proxy,,服务器地址,验证时间,存活时间)内容如图:提取具体内容
代码如下:

 total_good_ip  = []
        tr_list = html_etree.xpath("//tr[@class='odd'] | //tr[@class='']" )  # 获取的数量增加一倍,到达100个
        print("="*100)
        print(len(tr_list))
        for tr in tr_list:
            item= {}
            proxy_value= tr.xpath("./td[2]/text()")[0]+ ":" + tr.xpath("./td[3]/text()")[0] #123.161.160.74:8080形式
            #print(proxy_value)
            # 如果IP有效就加入到列表
            good_proxy = self.test_proxy_value(proxy_value)   # 传入字符串形式数据
            #print(good_proxy)
            if  good_proxy is not None:
                item["good_proxy"] = good_proxy    # 123.161.160.74:8080形式的可用IP
                if tr.xpath("./td[4]/text()") == [] :
                    item["ip_location"] = "无"
                else:
                    item["ip_location"] = tr.xpath("./td[4]/text()")[0]

                item["test_time"] = tr.xpath("./td[8]/text()")[0]  # 验证时间
                item["live_time"] = tr.xpath("./td[7]/text()")[0]  # 存活时间
                total_good_ip.append(item)
                #print(item)
        # 4.保存到本地
               # self.save2txt(item)  # 如果保存到本地,IP地址不方便去重,不过可以保存成CSV格式文件
        # 5.保存到数据库,
                self.save2mysql(item)

注意事项:

# 获取的数量增加一倍,到达100个 : tr_list = html_etree.xpath("//tr[@class='odd'] | //tr[@class='']" ) 

这里写图片描述
2.验证该ip地址是否有效: good_proxy = self.test_proxy_value(proxy_value) # 传入字符串形式数据
代码如下(随便找了几个网址做测试,后期可以建一个类似的池,像政府,教育之类的网址一般比较好找):



    def test_proxy_value(self,proxy): # 传入字符串形式的参数
        try:
            proxy_host = proxy
            protocol = 'https' if 'https' in proxy_host else 'http'
            proxies = {protocol: proxy_host}
            test_url_list=["https://hao.360.cn/?src=bm","https://www.baidu.com","https://www.163.com/","https://www.taobao.com/","https://www.tongji.edu.cn/","http://www.ruc.edu.cn/","http://www.bjfu.edu.cn",
                           "https://www.sina.com.cn/","https://www.jd.com/","http://www.qq.com/","http://www.meituan.com/"]

            test_url = random.choice(test_url_list)   # choice 传入的参数是列表
            print(test_url)  # 看此时的测试网址,确实是随机变化的!!
            response = requests.get(test_url,headers=self.headers, proxies=proxies, timeout=3)
            if response.status_code != 200:
                return None
            else:
                return proxy
        except Exception as e:
            print(e)
            print("*"*100)  #测试错误信息
            return None

3.注意字符串,列表,元组的相互转化:
数据类型相互转化

四。保存到mysql数据库
代码如下:

 def save2mysql(self,item):
        conn = pymysql.connect(host='localhost',port =3306,database ="IP_POOL" ,user='root',password='********',charset='utf8')  
        cur = conn.cursor()
        # 首先应该先创建ip_pool库,然后在创建ip_list表
        print(item)
        #创建iP_list表  #下面创建语句,执行一次就可以了,后期如果再执行会报错
        # sql = """
        #         create table ip_list(
        #         id int unsigned primary key auto_increment  not null,
        #         good_proxy varchar(40) not null,
        #         ip_location varchar(40) not null,
        #         live_time varchar(20) not null,
        #         test_time varchar(20) not null)DEFAULT CHARSET=utf8;
        # """
        # mysql添加语句(1.先检查该ip地址是否重复。 2.不重复就添加)
        sql_judge = """select good_proxy from ip_list where good_proxy=(%s)"""
        count_num = cur.execute(sql_judge,(item["good_proxy"]))
        print("查询到{}有{}条数据:".format(item["good_proxy"],count_num))
        if count_num > 0:
            print("已经有该IP地址了")
        else:
            sql_add = '''
              insert into ip_list(good_proxy,ip_location,live_time,test_time) values(%s,%s,%s,%s);
            '''
            try:
                count = cur.execute(sql_add,(item["good_proxy"],item["ip_location"],item["live_time"],item["test_time"]))
                print(count)
                conn.commit()
                print("添加数据成功")
            except Exception as error:
                print(error)
        conn.commit()  # 确认再次提交一次
        cur.close()
        conn.close()

到这里其实ip代理池的项目算是可以基本使用了,测试的结果如下图:
测试结果
结果在Navicat中的结果显示
虽然代码在添加之前会有good_proxy的是否重复的判断:
判断是否重复以及添加方式
,但是可能会存在一个问题:前期已经存在的ip地址失效了
解决措施:1.应该可以再建立一个函数,对所有已经存在的IP地址进行遍历检测是否还可以正常使用(放在最后面在执行程序)!
代码如下:

 
 def check_mysql(self):
        conn = pymysql.connect(host='localhost', port=3306, database="IP_POOL", user='root', password='******',charset='utf8')  # 这里是否要重新建立数据库呢?
        cur = conn.cursor()
        # mysql先提取数据,进行判断IP有效性
        count_total = cur.execute("select good_proxy from ip_list")
        print("测试:查询到%d条数据:" % count_total)  # 得到元组形式的信息
        # test_total_num = cur.fetchall()  # 这种测试是可以提取所有数据的
        # print(test_total_num)
        pur_count_tuple_list = cur.fetchall()  # 得到一个元组  ,cur.fetchone()为什么有时候取到的是None类型
        for pur_count_tuple in pur_count_tuple_list:

            # 获取查询的结果

            # 打印查询的结果
            print("测试:得到一个{}元组类型".format(pur_count_tuple))
            if pur_count_tuple !=None:
                pur_count_str = "".join(list(pur_count_tuple))  # 转换为字符串

                print("测试:得到一个{}字符串类型".format(pur_count_str))
                good_proxy = self.test_proxy_value(pur_count_str)
                # 获取查询的结果
                if good_proxy ==None: # 该IP地址失效,就删除该IP地址所在的行
                    # 删除对应的IP地址之后,剩下的数据应该自动补上id号
                    try:
                        count = cur.execute( 'delete from ip_list where good_proxy=pur_count_tuple')  # pur_count_tuple 还是pur_count_str呢?
                        conn.commit()
                        print("删除无效IP成功")
                    except Exception as error:
                        print(error)
                else:
                    print("该{}地址有效".format(good_proxy))
        conn.commit() # 多添加一次确认提交
        cur.close()
        conn.close()

2.或许也可以每次使用ip代理的时候先把之前的iP_list表给删除,每次都重建一个,使用Navicat也许操作比较方便运行前先把数据库清零

总结:
1.该小型ip代理池,满足日常学习获取数据的要求,对爬虫学习的很有帮助。比如基本爬虫的经典四步法有了更加清楚的认识,对xpath获取网页数据更加熟练,对保存到mysql数据库(增删改查,去重),对基本数据类型的理解,也可以保存到本地并读取数据,!此外随时使用的时候就可以运行,减少金钱成本,没必要保持一直动态进行筛选!项目的具体资料:
https://download.csdn.net/download/qq_33125039/10636941
2.获取的ip地址也可以保存在本地,然后在从本地读出,但是注意文件的格式
3.大家有什么好的想法和意见欢迎留言,多多交流,以上只是个人的理解,如有错误,还望大神指出,感谢!本人QQ:1143132860
4.大致参考资料:
(1)https://blog.csdn.net/anya/article/details/6407280/

代码下载网址:

点击直接下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值