15《Python 原生爬虫教程》爬虫和反爬虫

Python08

15《Python 原生爬虫教程》爬虫和反爬虫,第1张

有的时候,当我们的爬虫程序完成了,并且在本地测试也没有问题,爬取了一段时间之后突然就发现报错无法抓取页面内容了。这个时候,我们很有可能是遇到了网站的反爬虫拦截。

我们知道,网站一方面想要爬虫爬取网站,比如让搜索引擎爬虫去爬取网站的内容,来增加网站的搜索排名。另一方面,由于网站的服务器资源有限,过多的非真实的用户对网站的大量访问,会增加运营成本和服务器负担。

这是一种最基本的反爬虫方式,网站运营者通过验证爬虫的请求头的 User-agent,accep-enconding 等信息来验证请求的发出宿主是不是真实的用户常用浏览器或者一些特定的请求头信息。

通过 Ajax,或 者javascript 来动态获取和加载数据,加大爬虫直接获取数据的难度。

这个相信大多数读者非常熟悉了吧,当我们输错多次密码的时候,很多平台都会弹出各种二维码让我们识别,或者抢火车票的时候,会出现各种复杂的验证码,验证码是反爬虫措施中,运用最广,同时也是最有效直接的方式来阻止爬虫的措施之一。

在识别到某些异常的访问的时候,网站运营者会设置一个黑名单,把一些判定为爬虫的IP进行限制或者封杀。

有些网站,没有游客模式,只有通过注册后才可以登录看到内容,这个就是典型的使用账号限制网站,一般可以用在网站用户量不多,数据安全要求严格的网站中。

我们可以在请求头中替换我们的请求媒介,让网站误认为是我们是通过移动端的访问,运行下面的代码后,当我们打开 hupu.html,我们会发现返回的是移动端的虎扑的页面而不是网页端的。

比如,我们可以设置一个随机的间隔时间,来模拟用户的行为,减少访问的次数和频率。 我们可以在我们爬虫的程序中,加入如下的代码,让爬虫休息3秒左右,再进行爬取,可以有效地避开网站的对爬虫的检测和识别。

代理就是通过访问第三方的机器,然后通过第三方机器的 IP 进行访问,来隐藏自己的真实IP地址。

由于第三方代理良莠不齐,而且不稳定,经常出现断线的情况,爬取速度也会慢许多,如果对爬虫质量有严格要求的话,不建议使用此种方法进行爬取。

可以通过动态的 IP 拨号服务器来变换 IP,也可以通过 Tor 代理服务器来变换 IP。

反反爬虫的策略,一直是在变换的,我们应该具体问题具体分析,通过不断的试错来完善我们的爬虫爬取,千万不要以为,爬虫程序在本机调试之后,没有问题,就可以高枕无忧了。线上的问题,总是千变万化,我们需要根据我们的具体反爬措施,来针对的写一些反反爬虫的代码,这样才能保证线上环境的万无一失。

刚看了下虎扑的帖子。帖子的浏览量是动态加载的。并不是静态页面。所以常规的爬虫爬取的内容是空的。目前我了解的有两种方法可以去获取浏览量。一种是使用selenium + chrome。模拟浏览器加载。这种对于动态加载的页面比较有效。缺点就是效率太低。虎扑的帖子不建议使用(用不上)。另外一种就是找到虎扑获取浏览量的请求链接。看截图:

通过截图不难发现是通过图中的链接去获取的浏览量。该链接有两个参数。其中tid就是帖子的ID也就是每个帖子后面的ID。对比一下就发现了。最后的那个参数看起来很像是毫秒级的时间戳。在线验证一下如下图。

验证结果显示果然是时间戳(其实这个参数有没有都无所谓)。参数弄明白了就好办了直接将参数组合到该接口中去然后调用组合好的接口就可以了。是不是很简单~~~

希望可以帮到你,如有问题可以继续追问。谢谢

作为一名从小就看篮球的球迷,会经常逛虎扑篮球及湿乎乎等论坛,在论坛里面会存在很多精美图片,包括NBA球队、CBA明星、花边新闻、球鞋美女等等,如果一张张右键另存为的话真是手都点疼了。作为程序员还是写个程序来进行吧!

所以我通过Python+Selenium+正则表达式+urllib2进行海量图片爬取。

运行效果:

http://photo.hupu.com/nba/tag/马刺

http://photo.hupu.com/nba/tag/陈露

源代码:

# -*- coding: utf-8 -*-

"""

Crawling pictures by selenium and urllib

url: 虎扑 马刺 http://photo.hupu.com/nba/tag/%E9%A9%AC%E5%88%BA

url: 虎扑 陈露 http://photo.hupu.com/nba/tag/%E9%99%88%E9%9C%B2

Created on 2015-10-24

@author: Eastmount CSDN

"""

import time  

import re  

import os

import sys

import urllib

import shutil

import datetime

from selenium import webdriver  

from selenium.webdriver.common.keys import Keys  

import selenium.webdriver.support.ui as ui  

from selenium.webdriver.common.action_chains import ActionChains

#Open PhantomJS

driver = webdriver.PhantomJS(executable_path="G:\phantomjs-1.9.1-windows\phantomjs.exe")

#driver = webdriver.Firefox()

wait = ui.WebDriverWait(driver,10)

#Download one Picture By urllib

def loadPicture(pic_url, pic_path):

pic_name = os.path.basename(pic_url) #删除路径获取图片名字

pic_name = pic_name.replace('*','') #去除'*' 防止错误 invalid mode ('wb') or filename

urllib.urlretrieve(pic_url, pic_path + pic_name)

#爬取具体的图片及下一张

def getScript(elem_url, path, nums):

try:

#由于链接 http://photo.hupu.com/nba/p29556-1.html

#只需拼接 http://..../p29556-数字.html 省略了自动点击"下一张"操作

count = 1

t = elem_url.find(r'.html')

while (count <= nums):

html_url = elem_url[:t] + '-' + str(count) + '.html'

#print html_url

'''

driver_pic.get(html_url)

elem = driver_pic.find_element_by_xpath("//div[@class='pic_bg']/div/img")

url = elem.get_attribute("src")

'''

#采用正则表达式获取第3个<div></div>再获取图片URL进行下载

content = urllib.urlopen(html_url).read()

start = content.find(r'<div class="flTab">')

end = content.find(r'<div class="comMark" style>')

content = content[start:end]

div_pat = r'<div.*?>(.*?)<\/div>'

div_m = re.findall(div_pat, content, re.S|re.M)

#print div_m[2]

link_list = re.findall(r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')", div_m[2])

#print link_list

url = link_list[0] #仅仅一条url链接

loadPicture(url, path)

count = count + 1

except Exception,e:

print 'Error:',e

finally:

print 'Download ' + str(count) + ' pictures\n'

#爬取主页图片集的URL和主题

def getTitle(url):

try:

#爬取URL和标题

count = 0

print 'Function getTitle(key,url)'

driver.get(url)

wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='piclist3']"))

print 'Title: ' + driver.title + '\n'

#缩略图片url(此处无用) 图片数量 标题(文件名) 注意顺序

elem_url = driver.find_elements_by_xpath("//a[@class='ku']/img")

elem_num = driver.find_elements_by_xpath("//div[@class='piclist3']/table/tbody/tr/td/dl/dd[1]")

elem_title = driver.find_elements_by_xpath("//div[@class='piclist3']/table/tbody/tr/td/dl/dt/a")

for url in elem_url:

pic_url = url.get_attribute("src")

html_url = elem_title[count].get_attribute("href")

print elem_title[count].text

print html_url

print pic_url

print elem_num[count].text

#创建图片文件夹

path = "E:\\Picture_HP\\" + elem_title[count].text + "\\"

m = re.findall(r'(\w*[0-9]+)\w*', elem_num[count].text) #<a href="http://www.aspku.com/tech/jiaoben/%3Ca%20href=" tech="" jiaoben="" python="" 270537.html"="" style="background: noneborder: nonepadding: 0pxmargin: 0pxtext-decoration: nonefont-family: Tahoma, Geneva, sans-serifcolor: rgb(59, 89, 152)">python/95398.html">爬虫图片张数

nums = int(m[0])

count = count + 1

if os.path.isfile(path):   #Delete file

os.remove(path)

elif os.path.isdir(path):  #Delete dir

shutil.rmtree(path, True)

os.makedirs(path)    #create the file directory

getScript(html_url, path, nums) #visit pages

except Exception,e:

print 'Error:',e

finally:

print 'Find ' + str(count) + ' pages with key\n'

#Enter Function

def main():

#Create Folder

basePathDirectory = "E:\\Picture_HP"

if not os.path.exists(basePathDirectory):

os.makedirs(basePathDirectory)

#Input the Key for search str=>unicode=>utf-8

key = raw_input("Please input a key: ").decode(sys.stdin.encoding)

print 'The key is : ' + key

#Set URL List Sum:1-2 Pages

print 'Ready to start the Download!!!\n\n'

starttime = datetime.datetime.now()

num=1

while num<=1:

#url = 'http://photo.hupu.com/nba/tag/%E9%99%88%E9%9C%B2?p=2&o=1'

url = 'http://photo.hupu.com/nba/tag/%E9%A9%AC%E5%88%BA'

print '第'+str(num)+'页','url:'+url

#Determine whether the title contains key

getTitle(url)

time.sleep(2)

num = num + 1

else:

print 'Download Over!!!'

#get the runtime

endtime = datetime.datetime.now()

print 'The Running time : ',(endtime - starttime).seconds

main()