最近在做爬虫,但是一直遇到ip被封的问题,就想到了去自建一个ip代理池。
目标地址:西刺
http://www.xicidaili.com/nt/ # xicidaili国内普通代理
http://www.xicidaili.com/nn/ # xicidaili国内高匿代理
http://www.xicidaili.com/wn/ # xicidaili国内https代理
http://www.xicidaili.com/wt/' # xicidaili国外http代理
还可以使用其他的代理网站66ip,data5u,proxydb
用到的第三方包:
import requests import threading from bs4 import BeautifulSoup import random import sqlite3 from fake_useragent import UserAgent
整体思路:
第一步:创建sqlite3数据库和表
def creatdb(): try: conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql = '''create table ip ( ip CHAR(50) PRIMARY KEY NOT NULL)''' cursor.execute(sql) cursor.close() except: print("已经创建ip表")
第二步:爬取目标网站IP
def findip(type, pagenum, targeturl): # ip类型,页码,目标url,存放ip的路径 list = {'1': 'http://www.xicidaili.com/nt/', # xicidaili国内普通代理 '2': 'http://www.xicidaili.com/nn/', # xicidaili国内高匿代理 '3': 'http://www.xicidaili.com/wn/', # xicidaili国内https代理 '4': 'http://www.xicidaili.com/wt/'} # xicidaili国外http代理 url = list[str(type)] + str(pagenum) # 配置url headers = getheaders() # 定制请求头 html = requests.get(url=url, headers=headers, timeout=5).text soup = BeautifulSoup(html, 'lxml') all = soup.find_all('tr', class_='odd') for i in all: t = i.find_all('td') ip = t[1].text + ':' + t[2].text is_avail = checkip(targeturl, ip) if is_avail == True: print(ip) insertdb(ip)
第三步,验证目标IP是否可用
def checkip(targeturl, ip): headers = getheaders() # 定制请求头 proxies = {"http": "http://" + ip, "https": "http://" + ip} # 代理ip try: response = requests.get(url=targeturl, proxies=proxies, headers=headers, timeout=5).status_code if response == 200: return True else: return False except: return False
第四步,目标ip可用插入数据库表
def insertdb(ip): conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql = ''' insert into ip (ip) values (:st_ip)''' try: cursor.execute(sql, {'st_ip': ip}) except: print("已经有了") conn.commit() cursor.close()
如果程序比较久没有使用想要清空数据库中的数据,可以使用以下程序
def truncatedb(): conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql = "DELETE FROM ip" cursor.execute(sql) cursor.close()
查询全部的表数据
def selectalldb(): conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql = "select rowid,ip from ip" results = cursor.execute(sql) all_students = results.fetchall() all_students=list(all_students) conn.commit() cursor.close() return all_students
查询表中随机的单个数据
def selectdb(): conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql = "select rowid,ip from ip" results = cursor.execute(sql) all_students = results.fetchall() all_students=list(all_students) rain=random.randint(0, len(all_students)-1) ip=(list(all_students)[rain][1]) conn.commit() cursor.close() return ip
删除数据库表的指点的数据,这个用于再次的ip验证,可删除没有的数据
def deletedb(ip): conn = sqlite3.connect('ip.db') cursor = conn.cursor() sql ="delete from ip where ip ='"+ip+"'" cursor.execute(sql) conn.commit() cursor.close()
对于反反爬虫,请求头的修改是很有必要的,这里fake_useragent包,是一个很便捷的请求头的包
def getheaders(): ua = UserAgent() headers = {'User-Agent': ua.random} return headers
单线程进行捉取太浪费时间了,不想等,于是使用了多线程四种类型ip,每种类型取前8页,共32条线程
def getip(targeturl): threads = [] for type in range(4): # 四种类型ip,每种类型取前8页,共32条线程 for pagenum in range(0,8): t = threading.Thread(target=findip, args=(type + 1, pagenum + 1, targeturl)) threads.append(t) print('开始爬取代理ip') for s in threads: # 开启多线程爬取 s.start() for e in threads: # 等待所有线程结束 e.join() print('爬取完成')
构建proxies,在使用前对ip进行验证,删除无用ip
def getproxies(): ip=selectdb() targeturl = 'http://www.cnblogs.com/rianley/' # 验证ip有效性的指定url is_avail = checkip(targeturl, ip) if is_avail == True: proxies = {"http": ip, "https": ip} # 代理ip print("我有了") print(ip) return proxies else: deletedb(ip) print("删除"+ip) getproxies()
使用定时器对目标网站一定时间后运行。可以跟爬虫程序同时运行。
def running(): truncatedb() # 爬取前清空数据库 targeturl = 'http://www.cnblogs.com/rianley/' # 验证ip有效性的指定url getip(targeturl) if __name__ == '__main__': n=300 while True: print("--------------------------------------") running() # 此处为要执行的任务 time.sleep(n)
这种简便的ip池构建方便、而且能保证小需求的爬虫。加入的数据库后,爬虫程序可以直接去数据库取数据。
使用方法:
from ipdaili import getproxies
resp = requests.get(url, headers=headers,proxies=proxies(), timeout=5)
自建多线程ip池就先做到这里,后面希望能通过其他方式提高ip质量和爬虫效率。
代码存放在码云:https://gitee.com/qq903165495/self_built_ip_pool