之前做了一个爬取淘宝图片的爬虫,当然爬取少量信息肯定没问题,但是一旦爬取的信息量增加,就一定要注意反爬了。我一度以为我是一个好公民,我也不会贪心,每次就只会爬几页的东西,可是就在今天,我被淘宝和新浪封IP了,一脸无辜啊,好吧,还是得做点东西来防止被封了。目前我就学到要模拟浏览器、控制爬取数量和速度、代理IP这几招了,今天就想解决IP代理这事儿。
先说说思路吧:先去有免费代理的网站,将上面的IP代理全部爬下来,当然并不是所有的都有效,所以要检验它们是否可用,将可用的作为返回值,并将其写入csv文件(目前还没学到数据库,所以只能先放在本地文件了),然后要用时,就将其读取出来,或者将该.py文件作为一个模块,在另一个函数中引入该模块,这样就可以在应用时又执行一遍该代码,保证得到的实时有效的IP。这些IP是在一个列表中的,然后只需要利用random.choice()就可以随机提出一个来用(这样是为了让IP是换着用的,降低被封的可能)。
现在说说各个阶段的做的事吧。下面是我的实现功能的调用函数也是主函数
def main():
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)\
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
url = 'http://www.xicidaili.com/'
html = get_html(url, headers) # 得到页面的html
try:
http_item, https_item = get_AllIP(html) # 利用xpath得到所有的IP以及信息
proxiess = get_proxies(http_item, https_item) # 将所有IP整理得到IP的地址和端口构成的字典
usable_IP = get_usableIP(headers, proxiess) # 检验所有IP后,得到有效的IP
write_to_file(usable_IP) # 将得到的有用的IP写入文件保存
return usable_IP
except Exception as er:
print(er)
个人习惯,我比较喜欢先写主函数,其他的函数命名好之后先pass,知道它的具体功能就行,在主函数中实现整个代码的框架。
http_item, https_item = get_AllIP(html) # 利用xpath得到所有的IP以及信息
proxiess = get_proxies(http_item, https_item) # 将所有IP整理得到IP的地址和端口构成的字典
这两句代码是先得到代理类型为http和https的两个列表,然后通过get_proxies()函数将其构造为直接可用的proxies,proxiess为一个装了所有proxies(字典类型)的列表。然后通过get_usableIP()函数检验筛选出有效IP并返回给usable_IP,最后写入文件,将usable_IP 返回是为了其他模块调用时可以将该代码重新执行一遍,得到实时有效的IP。然后就是根据这个思路编写每个函数怎么实现它们的功能了。下面放实现函数功能的代码
先是获取西刺代理的页面的html
def get_html(url, headers): # 得到页面的html
try:
r = requests.get(url, headers = headers, timeout = 20)
if r.status_code == 200:
return r.text
except Exception as e:
print(e)
然后爬取和利用xpath表达式得到数据、并得到http_item和https_item列表的函数写的有点复杂,就先不放出来,什么时候有时间再改一下在记录一下。不过从中更加深刻的理解了字典,列表,字符串的关系,也是值得的。
def get_proxies(http_item, https_item): # 得到一个由完整proxies组成的列表
http_https = [] # 所有IP构造完成之后的容器
for i in range(0, len(http_item)):
proxy = {'http':'http://'+http_item[i]}
http_https.append(proxy)
for i in range(0, len(https_item)):
proxy = {'https': 'https://'+https_item[i]}
http_https.append(proxy)
return http_https
这个函数是将http_item和https_item两个列表构造成需要的以字典为元素的列表。其中又有一个知识点,在上一篇文章中说到列表、字典、字符串之间的转化时,说列表不能转化为字典,其实不是,例如
proxiess = dict(zip(ips, dks))
ips和dks均为列表,这段代码的功能是:将两个列表分别作为一个字典的key和value。
def get_usableIP(headers, proxiess): # 从所有IP中挑选出有用的IP并返回
usableIP = [] # 检查后有用的IP集合,总体为列表,个体为字典形式
url = 'https://www.taobao.com/'
for proxy in proxiess:
try:
data = requests.get(url, headers = headers, proxies = proxy, timeout = 5)
if data.status_code == 200:
usableIP.append(proxy) # 筛选有用IP
else:
pass
except:
pass
return usableIP
这个函数是筛选有效IP,我不太确定这个思路对不对,如果有幸有朋友可以看到,希望不不吝赐教。
def write_to_file(usable_IP): # 将有用的IP写入文件,便于使用
file = open('IP_agent.csv', 'w')
file.write('\n')
file.close() # 将现有文件中的数据清除,以免下一步写入时内容重复
for i in range(len(usable_IP)):
with open('IP_agent.csv', 'a') as f:
f.write(str(usable_IP[i]))
f.write('\n')
这是写入文件的代码,没什么好解释的。
大致就是这样了,因为没有设置输出即print,所以现在加上一句print(usable_IP),有效IP显示部分结果为
这样就可以在其他模块内调用该结果了。