2019-04-29

爬取今日头条 街拍数据---反爬策略滑动验证码

爬取的主页:https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D

今日头条是一个js动态加载的网站

我一开始用的requests库通过接口爬取,但是发现其url请求有一个timestamp请求,一个时间戳的请求,百度了一下,发现这应该是今日头条新的反爬策略(“萌新猜测!!”),,无奈,,从未遇到这种问题,,没解决掉。然后开始尝试selenium库自动化爬取

通过selenium库进行爬取,代码如下


结果不如人意,出现了验证码,这应该就是今日头条的反爬策略,只有把这个验证码破解了,才能得到想要的数据


滑动验证码

这也是我第一次接触到反爬验证码,在一波百度学习之后,思路如下:

由于这个验证码是自动跳出的,所以我们直接就能获取 

步骤1  :没有缺口的图片--未操作的验证码

步骤2 :获取带缺口的图片

步骤3 :对比2张图片的不同,得到不一样的像素点的x值,即要移动的距离。

步骤4 :模拟人的行为(先匀加速拖动再匀减速拖动,)把需要拖动的距离分为一段段的轨迹 

步骤5 : 实施拖动的过程,完成验证

步骤7: 获取数据

from selenium.webdriver.common.byimport By

from PILimport Image

from ioimport BytesIO

from selenium.webdriver.common.action_chainsimport ActionChains

import time

import re

import json

from bs4import BeautifulSoup

def get_snap(driver):#对整个网页截图,保存成图片,然后用PIL.Image拿到图片对象

    '''

对整个网页截图,保存成图片,然后用PIL.Image拿到图片对象

    :return: 图片对象

'''

    driver.get_screenshot_as_file('snap.png')

page_snap_obj=Image.open('snap.png')

return page_snap_obj

def get_image(wait,driver):#从网页的网站截图中,截取验证码图片,图片的获取

    '''

从网页的网站截图中,截取验证码图片

    :return: 验证码图片

'''

    img = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'validate-main')))

time.sleep(2)# 保证图片刷新出来

    print(img)

localtion = img.location

size = img.size

top = localtion['y']

bottom = localtion['y'] + size['height']

left = localtion['x']

right = localtion['x'] + size['width']

page_snap_obj = get_snap(driver)

crop_imag_obj = page_snap_obj.crop((left, top, right, bottom))

return crop_imag_obj

def get_distance(image1, image2):

'''

拿到滑动验证码需要移动的距离

:param image1:没有缺口的图片对象

:param image2:带缺口的图片对象

:return:需要移动的距离

'''

    # 拿到滑动验证码需要移动的距离

# :param

# image1: 没有缺口的图片对象

# :param

# image2: 带缺口的图片对象

# :return:需要移动的距离

    start =57

    threhold =60

    for iin range(start, image1.size[0]):

for jin range(image1.size[1]):

rgb1 = image1.load()[i, j]

rgb2 = image2.load()[i, j]

res1 =abs(rgb1[0] - rgb2[0])

res2 =abs(rgb1[1] - rgb2[1])

res3 =abs(rgb1[2] - rgb2[2])

# print(res1,res2,res3)

            if not (res1 < threholdand res2 < threholdand res3 < threhold):

return i -7

    return i -7

def get_tracks(distance):

'''

拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速

匀变速运动基本公式:

①v=v0+at

②s=v0t+½at²

③v²-v0²=2as

    :paramdistance: 需要移动的距离

    :return: 存放每0.3秒移动的距离

'''

    # 初速度

    v =0

    # 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移

    t =0.3

    # 位移/轨迹列表,列表内的一个元素代表0.2s的位移

    tracks = []

# 当前的位移

    current =0

    # 到达mid值开始减速

    mid = distance *4 /5

    while current < distance:

if current < mid:

# 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细

            a =2

        else:

a = -3

        # 初速度

        v0 = v

# 0.2秒时间内的位移

        s = v0 * t +0.5 * a * (t **2)

# 当前的位置

        current += s

# 添加到轨迹列表

        tracks.append(round(s))

# 速度已经达到v,该速度作为下次的初速度

        v = v0 + a * t

return tracks

def main():

driver = webdriver.Chrome()

driver.get('https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D')

wait = WebDriverWait(driver, 20)

# 步骤二:拿到没有缺口的图片

    image1 = get_image(wait,driver)

# 步骤三:点击拖动按钮,弹出有缺口的图片

    button = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'validate-drag-button')))

button.click()

# 步骤四:拿到有缺口的图片

    image2 = get_image(wait,driver)

print(image1,image1.size)

print(image2,image2.size)

# 步骤五:对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离

    distance = get_distance(image1, image2)

print(distance)

# 步骤六:模拟人的行为习惯(先匀加速拖动后匀减速拖动),把需要拖动的总距离分成一段一段小的轨迹

    tracks = get_tracks(distance)

print(tracks)

print(image1.size)

print(distance, sum(tracks))

# 步骤七:按照轨迹拖动,完全验证

    button = driver.find_elements_by_class_name('ovalidate-drag-button')

ActionChains(driver).click_and_hold(button).perform()

for trackin tracks:

ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

else:

ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform()# 先移过一点

        ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform()# 再退回来,是不是更像人了

    time.sleep(0.5)# 0.5秒后释放鼠标

    ActionChains(driver).release().perform()

shixian(driver)

这就是验证的代码(说实话,我也不是特别理解算法),再执行shixian()函数,进行爬取Json的动态网页

def shixian(driver):

for jin range(0,1000,20):    #offset每20 换一页,所以这边要设置了从offset=0 为第一页开始爬取,步数为20,到1000停止爬取,每一页数据,不过这边会出错,因为还没到1000就没有数据可以爬了。(其实只有7页,也就是0ffset=140!)

url ="https://www.toutiao.com/api/search/content/?aid=24&app_name=web_search&offset={}&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&en_qc=1&cur_tab=1&from=search_tab&pd=synthesis&timestamp=1556371760933".format(j)   #这就是今日头条的json页面,我们要爬取的数据都在者上面

driver.get(url=url)

text = driver.page_source     #这边得到的数据不是个干净的json格式字符串,而是以html标签包裹的字符串,所以当用json.loads 处理时会报错。


后面还有很多数据未显示



pattern1 = re.compile(r'<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">')          #一个正则表达式

out1 = re.sub(pattern1,'',text) #通过re.sub ,用’‘来替换在text中匹配到的字符串,这样就做到了把不干净的html标签清除  下面同理

# print(out1)

        pattern =re.compile(r'</pre></body></html>')

data =re.sub(pattern,'',out1)

datad = json.loads(data)

# print(datad)

        shuju = datad['data']    #直接选出data 中的内容

for iin shuju:

print(i.get('abstract',''))          #因为data中的内容是字典形式,而且是大字典中包含小字典,所以用for 遍历每个小字典,再用字典的.get 查询每个小字典的相应 键对。.get(’查询的键‘ ,’默认的方式‘) (ps,默认的方式,就是当你字典中查不到出错时,就默认为空。来防止程序中断执行报错)

print(i.get('image_list',''))

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

推荐阅读更多精彩内容

  • 我们可以借助插件来做 打开插件,找到自己需要的验证码 筛选有用的路径 把对应的视图函数也拿过来,注意还需要一个ge...
    程序员之路阅读 1,328评论 0 1
  • 开始尝试用weka工具来做一些小示例,但是发现输出结果里有很多不了解的地方,比如这样的输出代表什么意思,完全看不明...
    月照寒江阅读 428评论 0 0
  • win10下appium-desktop连接真机步骤 1.安装jdk(网上搜一大把) 2.安装安卓sdk(网上搜一...
    无聊的人诶阅读 174评论 0 0
  • 看着暑假就要结束了,带着孩子出去玩的家庭陆陆续续往回走。 我也带着孩子向回走,可是回家的车票在网上查来查去也没有订...
    冬后春初阅读 162评论 1 4
  • 没有晚课的夜晚 喜欢望着宿舍外的天空 看它一点点变化 我想记录下所有美好的时刻 有一天 把它们 全部送给你呀!
    Taliwtikk阅读 171评论 0 0