python 爬虫之道高一尺,魔高一尺一

在做爬取网站信息的时候,通常网站都会这反爬虫设计,如果一个ip访问太过频繁,会被列入黑名单或者出现验证码需要输入。星期天在爬取58同城信息的时候也遇到这个问题,百度了一下,发现以下两个方法最为省心省力。

1.设置时间间隔

既然一个ip访问太过频繁会被列入黑名单,那就不频繁的访问,导入time包,每一次加载完成后就强制休眠2s。例如

import time
wb_data = requests.get("http://cn.58.com/bijibendiannao/33724988041130x.shtml")
time.sleep(2)

2.设置代理IP

方法1虽然很有效但是会浪费很多不必要的时间,既然同一个ip访问太频繁会被加入黑名单,那不同的ip访问也会解决这个问题。

代理ip获取地址

代理ip获取网站:http://www.xicidaili.com/nn/1
获取代理ip的时候一定要注意协议是http还是https,血泪教训,不然很可能发生狗血报错,找半天找不出原因,就是因为http与https的协议搞错。

def get_ip_list(url, headers):
    web_data = requests.get(url, headers=headers)
    soup = BeautifulSoup(web_data.text, 'lxml')
    ips = soup.find_all('tr')
    ip_list = []
    for i in range(1, len(ips)):
        ip_info = ips[i]
        tds = ip_info.find_all('td')
        ip_list.append(tds[5].text+'://'+tds[1].text + ':' + tds[2].text)

    return ip_list

验证代理ip

假如我们从上述代理ip的网站获取了如下ip:

IP_LIST ='''
    HTTP://61.135.217.7:80
    HTTPS://114.215.83.184:3128
    HTTP://122.114.31.177:808
    HTTP://123.56.89.238:60443
    HTTPS://49.79.193.138:61234
    HTTPS://183.159.93.28:18118
    HTTPS://183.159.80.14:18118
    HTTP://114.99.28.110:18118
    HTTPS://183.159.88.201:18118
    HTTPS://183.159.80.246:18118
    HTTP://49.79.193.93:61234
    HTTP://111.155.116.237:8123
    HTTPS://117.68.194.66:18118
    HTTPS://60.177.228.169:18118
    HTTPS://183.159.87.2:18118
    HTTPS://183.159.88.75:18118
    HTTP://183.159.83.235:18118
    HTTP://202.104.184.5:808
    HTTP://14.120.181.241:61234
    HTTP://14.118.254.216:6666
    HTTP://124.235.121.216:8118
'''

(再说一遍,这个ip前的http还是https要与代理ip网站上的类型相同)
获取的ip可能不能用,所以我们需要验证可以用的ip

def cip(ip):
    try:
        if ip.keys()[0]=="http":
            requests.get('http://ip.chinaz.com/getip.aspx',proxies={'http':ip["http"]},timeout=3)
        else:
            requests.get('http://ip.chinaz.com/getip.aspx', proxies={'https': ip["https"]}, timeout=3)
    except:
        # print("failure")
        return False
    else:
        print(ip)
        return  True

而这个验证ip我一开始以为验证过的就可以一直用了,没想到刚验证过的,一秒之后就不能用了,所以我是在使用ip的时候才验证,而不是验证好了存一边使用的时候在抓取,例如。

def get_random_ip(ip_list):#从上文的IP_LIST随机获取ip的函数
    proxy_list = []
    for ip in ip_list.split():
        proxy_list.append( ip)
    proxy_ip = random.choice(proxy_list)
    if proxy_ip[4] == "S":
        proxies = {'https': proxy_ip}
    else:
        proxies = {'http': proxy_ip}
    return proxies


proxy = get_random_ip(IP_LIST)#先随机获取一个ip
while (not cip(proxy)) :#验证ip,如果ip有效则不在继续获取ip
  proxy = get_random_ip(IP_LIST)#如果无效则继续获得ip
wb_data =requests.get(url,proxies=proxy)#使用代理ip获取数据

3.补充

如果不出意外,上面两点就可以满足爬取需求了,但是还是会发生很多奇葩报错,所以建议把,wb_data = requests.get()换成如下代码,否则很容易因为http连接太多报出错误。

requests.adapters.DEFAULT_RETRIES = 5 #重试连接次数
s = requests.session()
s.keep_alive = False
wb_data =s.get(url,headers=header,proxies=proxy)

如果使用多进程去爬取数据,建议加上try....except去包裹request请求,虽然这样可能得不到出错原因,但是可以保证程序平稳运行下去,否则会出现wb_data的UnboundLocalError: local variable 'wb_data' referenced before assignment错误:

    try:
        s = requests.session()
        s.keep_alive = False
        wb_data = s.get(url, headers=header, proxies=proxy)
        time.sleep(1)
        soup = BeautifulSoup(wb_data.text,"lxml")
        no_longer_exist =  soup.find("p", attrs={'class':'et'})
        if no_longer_exist:
            print "nolonger"
            none_list_info.insert_one({"url":url})
            pass
        else:
            title = soup.select("head > title")[0].text  if soup.find_all("title","") and soup.select("head > title").__len__()>0 else None
            price = soup.select("span.price")[0].text if soup.find_all("span","price") and soup.select("span.price ").__len__()>0 else None
            date =soup.select("li.time")[0].text if soup.find_all("li","time") and soup.select("li.time ").__len__()>0 else None
            area = list(soup.select("span.c_25d ")[0].stripped_strings) if soup.find_all("span","c_25d") and soup.select("span.c_25d ").__len__()>0 else None
            list_info.insert_one({"title":title,"price":price,"date":date,"area":area})
    except:
        time.sleep(2)
        print "error "

多进程运行可以使用Pool

from multiprocessing import Pool
pool = Pool()#python根据你电脑的cpu数去决定开启几个进程
pool.map(get_list_info,urllist.split() )#get_list_info(url)是通过给定url获取相应界面信息的函数,urllist是目标url的字符串。

还有requests请求中的header也可以尝试更换,如果不经常更换我也忘了会不会报错,建议还是随机选取一个:

Headers='''
    Mozilla/5.0 (Windows; U; Windows NT 5.2) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13:
    Mozilla/5.0 (iPhone; U; CPU like Mac OS X) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A93 Safari/419.3:
    Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1: 
    Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070309 Firefox/2.0.0.3: 
    Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070803 Firefox/1.5.0.12 
'''
def Random_header(Headers):
    header_list = []
    for header in Headers.split(':'):
        header_list.append(header.strip())
    proxy_header = random.choice(header_list)

    return proxy_header

header['User-Agent'] = Random_header(Headers)
s = requests.session()
s.keep_alive = False
wb_data = s.get(url, headers=header, proxies=proxy)

最后附上git地址,大家有兴趣的可以看一下:
https://github.com/lixiaozhe666/58project

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容