A Song of Python and Anaconda


  • Startseite

  • Archiv

  • Tags

豆瓣电影的检索爬虫【python】

Veröffentlicht am 2016-09-20

简介: 豆瓣网的电影分类比较清晰,比较了音乐板块,还是感觉电影板块用来做爬虫比较合适

1、在参考他文的基础上,进行了学习分析。本文将记录和探讨细节部分。

2、url定义为电影板块: https://movie.douban.com/

3、遇到大型网站数据抓取,尤其是海外站点,因为延时造成的失败经常发生,遇到这样的情况,则建议用ui的加载until功能,在本测试案例中没有使用,因为测试结果响应较快。

4、因为要从大量的数据进行排序筛选,所以xpath的路径要尽可能的精确,如果直接用firebug的自带xpath地址,在排序检索,并提交内容时,可能因为路径有一个层级的差别导致失败报错。尽管很多时候,这个差别在图标点击上的效果一样。所以也是坑之一。

5、在运行程序前,看下内存使用率,如果较高就重启后再运行爬虫,否则由于selenium的加载浏览器比较消耗内存,很可能在此状态下,浏览器的响应延缓较大,因此,需要写好print信息,或者logging信息,以更明确程序执行点。

6、多选项排序的时候,建议做成gui,这是因为可以减少后续使用的重复输入。

7、一般来说,热评总是不缺,但是长评对于新电影是可能空缺的,为此,务必要加载try–except方式,来规避这样的情况。在本案例中,第六名的电影,正好没有长评,如果没有try except,则程序会在第六条就跳出终止了。

8、功能实现,为简单,只按照豆瓣电影默认的按照热门—-按热门排序,爬取了前20的电影的名字,网址,热评和长评信息,

9、代码如下:

# coding:utf-8
# 改编,精简版
# python 3.5.2
# 豆瓣网排名抓取和影评抓取V1.0

import time
from selenium import webdriver
import selenium.webdriver.support.ui as ui

url = "https://movie.douban.com/"
browser = webdriver.Firefox()
browser1 = webdriver.PhantomJS()
browser.get(url)

SUMRESOURCES = 0

# 热门
browser.find_element_by_xpath("//*[@id=\"gaia_frm\"]/div[1]/div[1]/label[1]").click()

# 按热度排序
browser.find_element_by_xpath("//*[@id=\"gaia_frm\"]/div[3]/div[1]/label[1]").click()

# 加载更多
browser.find_element_by_xpath("//*[@id=\"gaia\"]/div[4]/a").click()
time.sleep(2)

def get_title():

    global SUMRESOURCES
    # 定义抓top 20的电影
    num = 20
    # 定义抓长评
    long = 1
    for i in range(1, num+1):
            try:
                # 抓第i个图的基本信息
                title_list = browser.find_element_by_xpath("//*[@id=\"gaia\"]/div[4]/div/a[%d]"%i)
                print('------------------NO--'+ ''+str(SUMRESOURCES+1) +'--------------------')
                print()
                print('电影名字:', title_list.text)
                film_link = title_list.get_attribute('href')
                print('电影链接:', film_link)
                SUMRESOURCES += 1
                get_detail(film_link,long)
            except:
                print('不能抓到影视信息')


def get_detail(url,long=0):
    browser1.get(url)

    # 简介内容
    jian_jie = browser1.find_element_by_xpath("/html/body/div[3]/div[1]/div/div[1]/div[3]/div/span[1]").text
    print('电影简介:', jian_jie)

    # 热门评论
    browser1.find_element_by_xpath("//*[@id=\"hot-comments-tab\"]").click()
    for i in range(1, 5):
        try:

            re_ping = browser1.find_element_by_xpath("//*[@id=\"hot-comments\"]/div[%d]/div/p"%i).text
            print('-----'+'热评:'+'------')
            print(u'最新热评:'+ re_ping)
        except:
            print('抓取热评失败')



    if long == 1:
        try:
            # 点开下拉三角,展开长评
            # 使用对应img里自带的class
            browser1.find_element_by_xpath("//img[@class='bn-arrow']").click()
            time.sleep(1)

            long_get = browser1.find_element_by_xpath("//div[@class='review-bd']/div[2]/div")

            if long_get.text.encode('utf-8')=='提示: 这篇影评可能有剧透':

                print('发现恶心的剧透!将跳过!')
                long_ping = browser1.find_element_by_xpath("//div[@class='review-bd']/div[2]/div[2]")
            else:
                long_ping = long_get
            print('----------------------------------------'+'长评:'+'----------------------------------------')
            print('长评:', long_ping.text)
        except:
            print('抓取长评失败')



if __name__=="__main__":
    get_title()

10、参考: Python自定义豆瓣电影种类,排行,点评的爬取与存储(进阶上

11、前20个热门影评带长评,看了下很长,只保留了1和6的电影信息,有兴趣的就看看,没兴趣就忽略:

D:\Anaconda3\python.exe C:/Users/Administrator/PycharmProjects/untitled1/test/blog.py
——————NO–1——————–

电影名字: 釜山行 8.3
电影链接: https://movie.douban.com/subject/25986180/?tag=%E7%83%AD%E9%97%A8&from=gaia
电影简介: 证券公司基金管理人石宇(孔侑 饰)光鲜精干,却也是个重利轻义之徒。妻子为此与之决裂,女儿秀安(金秀安 饰)则对如此自私的父亲越来越失望,决定前往釜山和母亲生活。在秀安生日这天,石宇抽出时间陪伴女儿登上开往釜山的特快列车。而与此同时,城市四处出现了极为可疑的暴动事件。政府极力洗白无法掩盖丧尸肆虐的事实,即便懵然无知的列车乘客也因为不速之客的到来而堕入恐慌绝望的地狱中。开车的刹那,一名感染者冲入车厢,而她很快尸变并对目光所及之处的健康人展开血腥屠杀。未过多久,丧尸便呈几何数爆发性地增长。石宇被迫和幸存者的乘客们在逼仄的空间中奋力求生。
通往釜山的遥遥旅途布满杀机,危难时刻每个幸存者的人性也承受巨大的考验……
—–热评:——
最新热评:一切灾难皆人性,唉,最后那一枪要是开了,就是神作了。
—–热评:——
最新热评:套路很深,煽情很猛!据说这部电影耗资100亿韩元,其中90亿用于几百名群演的霹雳舞教学费用。哦,对了,还要唱好歌,关键时候保命就靠他了。
—–热评:——
最新热评:僵尸进攻的部分比较过瘾,火车拖着一尾巴僵尸的部分视觉效果很有趣;人文部分十分韩剧,社会讽刺过于直接而显得无趣了,男主那洗衣液CF般的闪回、洗手间哭泣都太cheesy,其实马东锡才是英雄,只是被塑造得不壮烈罢了;镜头感、节奏感so so,演员们演得不够害怕,有的部分特别明显。拜托,是僵尸也!
—–热评:——
最新热评:比预想的好,《僵尸世界大战》的僵尸模式,虽然不可避免的出现了很多套路与恶意煽情的东西,但是,惊悚的氛围把握还是挺准确的
—————————————-长评:—————————————-
长评: 我记得好久以前,在我上次回国以前吧,悉尼的电影行业某朋友跟我提过她的老板投了一个韩国僵尸片,我当时就觉得投这个干嘛啦韩国拍的僵尸片必须没什么好看的嘛,毕竟“僵尸片是欧美的类型片”这个印象已经根深蒂固了。
后来《釜山行》出来,被各种好评,我挺惊讶。前两天看了个微博Po的推荐终于忍不住,今天约了朋友去看掉了。看完以后到现在三个小时了,我还感觉闷闷的,一面觉得“真好看呀”一面为我们中国电影被韩国电影抛在后面的、越来越遥远的距离感到焦虑。
《釜山行》就是一个典型的僵尸片,和我们看过的所有僵尸电影拥有完全一样的套路,有封闭空间,有感染有逃命,有对抗有小聪明,有煽情有生死,这里有的《行尸走肉》呀《僵尸肖恩》啊它们都有过。但是《釜山行》是真正意义上的属于亚洲的僵尸片,它充满了身为亚洲人会各种共鸣而欧美人绝对想不到用的元素与梗:亚洲社会独一份儿的伦理道德、人情世故、因果报应……全都被调进了故事里。
看一个僵尸片到最后不止被圆满地吓了一圈,还感动得五体投地,哭得稀里哗啦。我好几次以为自己扛过了哭点,没想到最后还是败给了一段父女的对话。眼泪止也止不住。
这个片子在你以为充满希望的时候突然就绝望了,又在你终于绝望以后留了一点希望。
剧本是工工整整的好莱坞商业大片的模式,第几分钟出现几个事件几个转折几个主要角色几对人物关系—-全部是教科书的模版,以最快速度发展故事,让每一分钟的情节都饱满生动(用饺子比喻的话就是塞满了肉馅),丝毫不用一点闲话家常来浪费镜头时间。
知道如何利用一个满是缺点的主角的成长与改变让观众代入角色(少年漫画的套路),知道怎么运用人气角色的命运来影响观众情绪,知道留一个情节上的“关键道具”(儿歌)并在正确的位置使用了三次……两个小时里十几个人物全部立住了,观众能清晰地分辨他们记住他们并对他们拥有不同的解读—-就人设这一点,多成功啊。从好莱坞学到的,已经完全变成自己的了。

几年前上学的时候,我的澳洲电影老师专门开了一节课讲韩国电影的崛起与风格,讲朴赞郁讲《老男孩》,当年让我一个对“韩国电影”四个字充满鄙视的无知少女差点跪着出了教室。我那时候觉得中韩两国电影的差距至少有10年那么多吧。
如今,这些年过去,我隐约觉得中国电影多少也有了一丢丢进步,结果看完《釜山行》,人家他妈的又一下子甩开了我们十多年。

怎么追啊。继续追吧。心累累的,哎。

——————NO–6——————–

电影名字: 我们这种叛徒 6.3
电影链接: https://movie.douban.com/subject/10461676/?tag=%E7%83%AD%E9%97%A8&from=gaia
电影简介: 牛津大学导师佩里和女友嘉儿在怡人的安提瓜岛上享受美妙的假期时,偶然结识了俄国富豪迪马——一场精彩的网球比赛让佩里和迪马的人生轨迹有了交集。谁料,迪马竟是俄国犯罪组织的洗钱专家,组织内部斗争的残酷令迪马萌生去意,于是他希望通过佩里向英国情报部门传达寻求政治庇护的请求……
自此,佩里和嘉儿渐渐脱离了正常的生活轨道,一系列政治阴谋、间谍行动扑面而来,就此开启了一场惊心动魄的跨国逃亡之旅:从法国巴黎到瑞士阿尔卑斯山,再到伦敦城里黑暗的走廊,哪里才是安全港湾?谁才是真正的叛徒?
—–热评:——
最新热评:点解会拣你?因为当时没有其他人啊。没得拣的情况下可以得到的最好结果。伊万最近几年都不行。
—–热评:——
最新热评:一万同志从角色设定到演技都毫无吸引力啊,四哥她爹演技还是有功底的(里面这女儿真是坑爹没商量),全部注意力都被Brody的fashion show吸引去了,玳瑁镜、围巾、风衣、三件套、居家服简直英国范儿到不行。剧情一般般啦,勒卡雷叔叔的水平应该不是这个level的吧……
—–热评:——
最新热评:比老婆收入低形象倒是挺符合,但是真的不适合长发。剧情没兴趣看。
—–热评:——
最新热评:3.5/5 摄影大加分!想金盆洗手奈何身不由己。Dima人物塑造得不错。
抓取长评失败

163和qq邮箱的自动登录--selenium【python】

Veröffentlicht am 2016-09-20

简介: 之前直接测试mail.q63.com 以及 mail.qq.com的selenium登录都受阻,网站采用了较强的反爬技术,如动态id等,故用规避方法登陆

1、在参考他文的基础上,做了代码重构。QQ邮箱在右上角有“基本版”登录,没有做加强反爬处理,而163的,则是通过www.163.com去找邮箱,发现接口是email.163.com,注意多了一个字母e,是较早的登录接口。

2、代码(请把你的帐号密码代替xxxx),增加了自动判断输入是否正确:

# coding:utf-8
# python 3.5.2
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import selenium.webdriver.support.ui as ui
import time

# 选择QQ还是163邮箱
email_type = input("1-QQ免费邮箱\n2-163免费邮箱\n请输入对应数字:")

def run():
    global email_type
    if email_type != str(1) or email_type != str(2):
        print ("输入错误,请重新输入 :)")
        email_type = input("1-QQ免费邮箱\n2-163免费邮箱\n请输入对应数字:")

    if email_type == str(1):
        url = "https://ui.ptlogin2.qq.com/cgi-bin/login?style=9&appid=522005705&daid=4&s_url=https%3A%2F%2Fw.mail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwsk%26delegate_url%3D%26f%3Dxhtml%26target%3D&hln_css=http%3A%2F%2Fmail.qq.com%2Fzh_CN%2Fhtmledition%2Fimages%2Flogo%2Fqqmail%2Fqqmail_logo_default_200h.png&low_login=1&hln_autologin=%E8%AE%B0%E4%BD%8F%E7%99%BB%E5%BD%95%E7%8A%B6%E6%80%81&pt_no_onekey=1"
        driver = webdriver.Firefox()
        driver.get(url)
        time.sleep(2)
        driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[4]/ul/li[1]/input").send_keys("xxxx")
        driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[4]/ul/li[2]/input").send_keys("xxxx")
        driver.find_element_by_xpath("//html/body/div[1]/div[2]/div[4]/div[2]").click()
        print('--------------Log In------------')
        time.sleep(1)


    elif email_type == str(2):
        url = "http://email.163.com/"

        driver = webdriver.Firefox()
        driver.get(url)
        time.sleep(2)
        driver.find_element_by_xpath("/html/body/div[1]/div[1]/div/div[2]/div[2]/div/form/div[1]/label").send_keys("xxxx")
        driver.find_element_by_xpath("/html/body/div[1]/div[1]/div/div[2]/div[2]/div/form/div[2]/label").send_keys("xxxx")
        driver.find_element_by_xpath("/html/body/div[1]/div[1]/div/div[2]/div[2]/div/form/div[2]/button").click()
        print('--------------Log In------------')
        time.sleep(1)


run()

3、pycharm输出:

1-QQ免费邮箱
2-163免费邮箱
请输入对应数字:4
输入错误,请重新输入 :)
1-QQ免费邮箱
2-163免费邮箱
请输入对应数字:2
————–Log In————

Process finished with exit code 0

4、参考:

【伪】解决动态id元素Selenium无法捕捉自动登录问题

关于Xpath地址的分析小结

Veröffentlicht am 2016-09-19

简介: 发现有时候遇到xpath的路径报错,然而使用的都是一些插件工具,但不同浏览器和不同插件得到的xpath又有所差别,故做一个测试记录

1、旁引: 因故装python 3 +2 的双蛇系统,是故再次要把anaconda配置到python 2 去然后搜网址的时候,看到一个评论,喜感,记录如下:

问:anaconda与python什么关系

答复:
python 是莽蛇,一般是陆上蛇
Anaconda 是美洲大水蛇。

好吧:如果英文不好的,可以用简友0han写的翻译小程序来看下:

===============================

=有道词典 命令行版v1.1 by 0han=

输入’q’可退出程式

请输入词语:python

翻译:n. 巨蟒;大蟒

请输入词语:anaconda

翻译:n. 水蟒;蟒蛇

请输入词语:


是不是可以写一部: 水与火之歌 :)

2、以豆瓣网电影板块的“热门”按键为例,如图:

在chrome里的xpath是:

//*[@id="gaia_frm"]/div[1]/div[1]/label[1]

在firefox 的firebug插件::

/html/body/div[3]/div[1]/div/div[2]/div[4]/div[2]/div[1]/form/div[1]/div[1]/label[1]

而firexfox的xpath checker插件则是:

id('gaia_frm')/x:div[1]/x:div[1]/x:label[1]

又测试QQ浏览器为:

//*[@id="gaia_frm"]/div[1]/div[1]/label[1]

可以发现,谷歌和qq浏览器的格式一致,但firefox的插件,则不尽相同,但最起码,倒过来看,还是基本相同,这其实是路径开头选择差异导致的,而到路径最后基本都一样,这可以理解为绝对路径和相对路径,前者最开始一个斜杠,后者2个斜杠。那即便后面就肯定一样?但还要看“后面”的层级定义,即便到达最后一级的标签,采用的是什么属性定位,比如通过id,通过name等的区别。

  • 其中,firefox的xpath checker插件显示的比较特别,带有X: 字样,估计是该插件自定义的xpath格式,但如果直接复制到python里,是不识别的,因此会报错。所以,如果要采用他的格式,需要把x: 给删掉。测试就通过了。也就是要修改成:

    driver.find_element_by_xpath(“id(‘gaia_frm’)/div[1]/div[1]/label[1]”)

  • 谷歌和qq的一样,只需要测试一个,结论直接通过:

    driver.find_element_by_xpath(“//*[@id=\”gaia_frm\”]/div[1]/div[1]/label[1]”)

  • firebug的,结论通过:

    driver.find_element_by_xpath(“/html/body/div[3]/div[1]/div/div[2]/div[4]/div[2]/div[1]/form/div[1]/div[1]/label[1]”

结论:

  • 谷歌和qq浏览器自带的xpath路径分析,可通过常规需求的测试(由于有隐藏元素的一些网页功能,遇到的话依然可能失败,还有就是动态刷新技术)
  • 由于我安装的firefox没看到自带的xpath分析功能,所以安装了firebug插件以及xpath checker插件,但xpath checker插件自带的格式却得不到浏览器的支持,需要特别注意。
  • xpath checker在反向验证xpath路径的时候还是有用。

关于最后一点展开下,也是经验总结:

比如,你看别人的代码分析,因为你不确定他是使用浏览器自带的,还是自己定义的,还是插件的xpath路径,甚至可能对方根本没有任何注释,导致你看到xpath路径的时候,一头的晕,丫到底写的是啥呀?也许聪明的你会说,那可以到网页源代码查找一部分的关键词,确实可以,但也麻烦,举例来说:

driver_item.find_element_by_xpath("//div[@class='list-wp']/a[@class='more']").click()

虽然可以知道要点击一个含有class=’more’的控件元素,但你会发现直接网页源代码木有!! 为何? 因为他的真实是双引号class=”more”
原来,因为selenium 的find_element_by_xpath(“XXX”) 命令,如果你把XXX用class=”more”直接代替,绝对的报错,为何,因为双引号冲突, 你可以反斜杠来区分,抑或用单引号,这就是原因所在。可见,即便你到网页源代码查找还是麻烦的很,更不要说,如果万一源代码里有好几个这样的查找单元了。

而我们用,xpath checker反向验证,可以很快的让你知道,对方分析的是什么元素,如下图:

stocksnap 一个不错的图片网站的图片抓取--selenium 右键保存和直接写入2个模式【python】

Veröffentlicht am 2016-09-18

参考:原文1

参考:原文2

1、原文1采用了scrapy方法,本文改编用selenium方法,并参考原文2首次采用模拟右键来保存图片。

2、网站分析:

首先发现鼠标拖动到图片底部区域,主页又不断加载新的图片,可判断是异步的。另单独查看2个图的xpath,发现总体格式一致,编号部分有差异:

/html/body/div[4]/div[3]/div[2]/div/div[1]/a/img

/html/body/div[4]/div[3]/div[2]/div/div[11]/a/img

这样我们就得到了在firefox下统一的xpath为,注意是删除div[i]部分,留下2个斜杠:

/html/body/div[4]/div[3]/div[2]/div//a/img

此时,可能觉得为啥要删除,而不是用正则式.*代替?测试那样的结果是Nan,也就是说xpath的格式和re格式不能混搭。

而每个jpg地址在src属性中,所以如果想查阅批量的图片地址,则:

/html/body/div[4]/div[3]/div[2]/div//a/img/@src

3、既然这么爽的得到了图片地址,剩下就是批量下载保存了:

这一次,先测试了用firefox模拟人工右键保存的方法,代码如下,保存那块还没整明白,也就是自动到出现图片保存的界面,根本原因是selenium无法操作操作系统级的对话框:

索性快速人工点保存,30个图的保存位置都是重复的,依次得到30个图:

4、随机打开一个图,如下,可见测试ok:

5、代码:

# -*- coding: utf-8 -*-
# python 3.5.2
# Author:vansnowpea
# stocksnap 一个不错的图片网站的图片,右键保存抓取

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys


print('Please wait...Firefox loading...')
print('---------------------------------')


url = "https://stocksnap.io/"

# 用浏览器实现访问
driver = webdriver.Firefox()
driver.maximize_window()
driver.get(url)

# 得到总的jpgs的路径集合
xpath = "/html/body/div[4]/div[3]/div[2]/div//a/img"

# set profile
fp = webdriver.FirefoxProfile()
fp.set_preference('browser.download.folderList', 2)
fp.set_preference('browser.download.manager.showWhenStarting', False)
fp.set_preference('browser.download.dir', './yourfolder/')
fp.set_preference('browser.helperApps.neverAsk.saveToDisk', 'image/jpeg')



# 保存图片,人工批量点保存,selenium无法操作操作系统级的对话框
for element in driver.find_elements_by_xpath(xpath):
    img_url = element.get_attribute('src')
    img_desc = element.get_attribute('data-desc')

    action = ActionChains(driver).move_to_element(element)
    action.context_click(element)
    action.send_keys(Keys.ARROW_DOWN)
    action.send_keys('v')
    action.perform()

print('Well done! all pictures downloaded.')
print('---------------------------------')

# driver.close()

6、如果图片数量少,人工保存下也无妨,但数量大肯定不行,所以还是用常规的自动写入数据保存的方式。另外此网站是通过ajax异步加载,当鼠标放到首页30个图的下方,也就是浏览器底部区域,他又会自动加载新的图片出来。而通过新的第一层代码的模拟鼠标下移,可以得到更多的图片。千万要注意的是,在python 3中,对数dict的关键词查找是in,比如:if n in previous:而在python 2 中是has_key,比如:if previous.has_key(n):对应代码为:

# python 3.5.2
from selenium import webdriver  
import time  
import urllib


# 爬取页面地址  
url = "https://stocksnap.io/"

# 目标元素的xpath  
xpath = "/html/body/div[4]/div[3]/div[2]/div//a/img"

# 启动Firefox浏览器  
driver = webdriver.Firefox()  

# 最大化窗口,因为每一次爬取只能看到视窗内的图片  
driver.maximize_window()  

# 记录下载过的图片地址,避免重复下载  
img_url_dic = {}  

# 浏览器打开爬取页面  
driver.get(url)  

# 模拟滚动窗口以浏览下载更多图片  
pos = 0  
m = 0 # 图片编号  
for i in range(10):  
    pos += i*500 # 每次下滚500  
    js = "document.documentElement.scrollTop=%d" % pos  
    driver.execute_script(js)  
    time.sleep(1)     

    for element in driver.find_elements_by_xpath(xpath):  
        img_url = element.get_attribute('src')  
        # 保存图片到指定路径  
        if img_url != None and not img_url in img_url_dic:

            img_url_dic[img_url] = ''  
            m += 1  
            ext = img_url.split('.')[-1]  
            filename = str(m) + '.' + ext  
            #保存图片数据  
            data = urllib.request.urlopen(img_url).read()
            f = open('./van/' + filename, 'wb')
            f.write(data)  
            f.close()  
driver.close()  

7、结果展示:相对第一个方法,获取了更多的图片:

Firefox不能运行selenium的故障排查

Veröffentlicht am 2016-09-17

说明:Firefox中文最新版48不能运行selenium2.53.6的故障排查

1、错误提示:

  File "D:\Anaconda3\lib\site-packages\selenium\webdriver\firefox\firefox_binary.py", line 103, in _wait_until_connectable
    raise WebDriverException("Can't load the profile. Profile "
selenium.common.exceptions.WebDriverException: Message: Can't load the profile. Profile Dir: %s If you specified a log_file in the FirefoxBinary constructor, check it for details.

2、排查版本: selenium已经是最新版2.53.6 firexfox也是最新中文版48

谷歌:

http://stackoverflow.com/questions/37693106/selenium-2-53-not-working-on-firefox-47/37693374

上面给了一个在selenium 在2.53.0时代,运行firefox 47版本的方法,感觉麻烦,所以我优选了退回低版本的策略,如下:

3、评估是否firefox的48最新版还不支持?所以到firefox官网上,直接看到的最后的老版本是47, 测试安装了中文版,结果一样,继续卸载看46版本,使用的以下网址:

https://ftp.mozilla.org/pub/firefox/releases/
https://ftp.mozilla.org/pub/firefox/releases/46.0.1/win64/en-US/

一下就成功了。

4、后来翻阅stackoverflow的帖子,发现有人反馈2.53.6已经支持firefox 48了。 但是我的咋就不行? 猜测区别就是中文和英文,所以我就把46版本卸载了测试48英文版,

https://ftp.mozilla.org/pub/firefox/releases/48.0b1/win64/en-US/

结果直接跳出firefox已停止工作。

5、结论:就2.53.6的selenium版本,测试firefox 46 英文版稳定运行。47和48版本失败。操作系统Win10,所以建议使用46版本的firefox。

基于Selenium一键写CSDN博客并做成exe文件【python】

Veröffentlicht am 2016-09-17

参考:原文1和原文2

1、代码,原文python2,修改成了python 3,作者信息保留,请修改CSDN帐号登录信息:

# -*- coding: utf-8 -*-
# python 3.5.2
#Author:哈士奇说喵
#CSDN--实现一键写博客

from selenium import webdriver
import time

#shift-tab多行缩进(左)
print ('Please wait...Firefox loading...')
print ('---------------------------------')
#reload(sys)

PostUrl = "https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn"
driver=webdriver.Firefox()#用浏览器实现访问
#driver = webdriver.PhantomJS(executable_path="phantomjs.exe")#没用浏览器
driver.get(PostUrl)


#账号填充输入
elem_user = driver.find_element_by_id('username')
elem_psw = driver.find_element_by_id('password')

#可以自己修改登录名和账户密码,我自己的隐去了
elem_user.send_keys('41111111@qq.com')
elem_psw.send_keys('1111111')


#点击登录
#click_login = driver.find_element_by_xpath("//input[@class='logging']")
click_login = driver.find_element_by_xpath("//input[@class='logging']")
click_login.click()
print( 'log in...')
print ('---------------------------------')
time.sleep(1)

#先点击写博客图标,不然元素隐藏

click_wbic = driver.find_element_by_xpath("//ul[@class='btns']/li[5]")
click_wbic.click()
print ('jumping...')
print ('---------------------------------')


click_choice = driver.find_element_by_xpath("//div[@class='wrap clearfix']/dl/dt[4]/a")
click_choice.click()#将点击操作放在内部比较好
#定位新页面元素,将handle重定位即可
driver.switch_to_window(driver.window_handles[1])#定位弹出的第一个页面,也就是当前页面
click_markdown = driver.find_element_by_xpath("//p[@class='subtit']/a")
click_markdown.click()
print ('---------------------------------')
print ('here we go!')
#关闭无关页面,也可以根据自己喜好保留无关页面
driver.close()#关闭第二个页面,也就是一般编辑器下的CSDN
driver.switch_to_window(driver.window_handles[0])#关闭第1个页面,也就是登录主页
driver.close()

2、代码分析:
一些按键的定位是使用了xpath的编写方式,以“登录”为例,右键,检查,然后找到最近的一个class,因为这个登录直接在一个class 里,如下代码:

<input class="logging" accesskey="l" value="登 录" tabindex="6" type="button" data-form-sbm="1474112762583.3015">

所以根据xpath的路径规则,是 //input[@class=’logging’],然后,配合selenium的xpath选定语法,写为:

click_login = driver.find_element_by_xpath("//input[@class='logging']")

而写博客的按键,有所小复杂,因为检查的时候,不是直接在类里,需要向上寻找一个父类,注意不是平行的类,因此代码相对复杂点,形如:

click_wbic = driver.find_element_by_xpath("//ul[@class='btns']/li[5]")

click_choice = driver.find_element_by_xpath("//div[@class='wrap clearfix']/dl/dt[4]/a")

click_markdown = driver.find_element_by_xpath("//p[@class='subtit']/a")

3、xpath的路径分析是直接通过检查中的代码换成xpath模式,而不是右键 copy–> copy xpath模式。

4、做成exe登录更简单些。

5、全文需要安装firefox,为了保证和selenium兼容,我的是46英文版。

6、又查阅了其他人的xpath分析方法,发现不一定要通过class来区分,如下:

<input type="text" name="passwd" id="passwd-id" />

这段html语言,可以用以下的几种方法来定位。

element = driver.find_element_by_id("passwd-id")
element = driver.find_element_by_name("passwd")
element = driver.find_elements_by_tag_name("input")
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

而且你在用 xpath 的时候还需要注意的是,如果有多个元素匹配了 xpath,它只会返回第一个匹配的元素。如果没有找到,那么会抛出 NoSuchElementException 的异常。

7、由于firefox的加载比较慢,所以想通过PhantomJS来测试,但是发现他不识别既定的xpath路径,应该说是部分不识别,开头的还是识别的,中间的报错,坑爹啊。

selenium+PhantomJS 抓取斗鱼房间信息【python】

Veröffentlicht am 2016-09-16

说明原文连接【点我】

1、环境:selenium+PhantomJS
selenium 可直接安装 : pip install -U selenium
PhantomJS: 官网下载,设置对应bin的路径为环境变量。

2、本文对原作的代码进行了改编,去掉了单元测试部分,因为重点是研究selenium+PhantomJS 抓取异步数据,最后把数据通过mysql导出。

3、代码():

#coding:utf-8
# python 3.5.2


from selenium import webdriver
from bs4 import BeautifulSoup
import pymysql.cursors



class Test(object):
    def __init__(self):
        pass



    def begin_run(self):

        driver = webdriver.PhantomJS()
        driver.get('http://www.douyu.com/directory/all')
        soup = BeautifulSoup(driver.page_source, 'xml')
        while True:
            titles = soup.find_all('h3', {'class': 'ellipsis'})
            # soup.find_all('h3', {class_='ellipsis'})
            nums = soup.find_all('span', {'class': 'dy-num fr'})
            for title, num in zip(titles, nums):
                data = {
                    '房间名': title.get_text(),
                    '观看数量': num.get_text()
                }
                connection = pymysql.connect(host='localhost',
                                     user='root',
                                     password='xxxx',
                                     db='douyu',
                                     charset='utf8'
                                     )

                try:
                    # 创建会话指针
                    with connection.cursor() as cursor:
                        # 创建sql语句
                        sql = 'insert into `douyu1` (`房间名`,`观看数量`) values(%s, %s)'
                        # 执行sql语句
                        cursor.execute(sql, (data['房间名'], data['观看数量']))

                        # 提交
                        connection.commit()
                finally:
                    connection.close()
            if driver.page_source.find('shark-pager-disable-next') != -1:
                break
            elem = driver.find_element_by_class_name('shark-pager-next')
            elem.click()
            soup = BeautifulSoup(driver.page_source, 'xml')

    def start(self):
        Test().begin_run()

if __name__ == "__main__":
    test = Test()
    test.start()

4、其中的坑:
如果默认使用webdriver的“.”查找功能,比如很可能你突然忘记PhantomJS的拼写了,那么查阅回车后,得到的是PhantomJS,注意不是PhantomJS() ,就会导致报错如下:

Error
Traceback (most recent call last):
  File "C:\Users\Administrator\PycharmProjects\untitled\readpdf.py", line 13, in testEle
    driver.get('http://www.douyu.com/directory/all')
TypeError: get() missing 1 required positional argument: 'url'

如果我们分别type他们的信息:

print(type(webdriver.PhantomJS))

print(type(webdriver.PhantomJS()))

得到如下结果:

<class 'type'>

<class 'selenium.webdriver.phantomjs.webdriver.WebDriver'>

也就是说,加了括号,表示得到的是selenium.webdriver.phantomjs.webdriver.WebDriver的具体对象。

5、测试结果:
~天天游戏,天天厨房~ 观看数量比较威猛,

6、原作加入了单元测试的写法,如果有兴趣,可以看下另一篇文章【点我】,对unittest做了有点详细的解释说明。

7、总结:本文学习了 的基本使用方法,另外必须强调的是翻页方面的操作,就斗鱼来说,在总网址下,翻页时在浏览器的地址是不变的,而之前抓取的网站都是跟着翻页变更地址的,形如xxx/1 xxx/2 这样的, 那么必须重点看下源代码的以下几句:

if driver.page_source.find('shark-pager-disable-next') != -1:
    break
elem = driver.find_element_by_class_name('shark-pager-next')
elem.click()
soup = BeautifulSoup(driver.page_source, 'xml')

其中if语句判断 没有下一页了 ,抓取就结束,不然,就通过模拟点击到下一页继续抓取数据。 另外,“下一页”是在名为shark-pager-next的一个类里的,所以那么写,而当到了38页,也就是最后一页后,那个“下一页”的图标就灰色了,通过查看代码,里面是在一个含有shark-pager-disable-next字样的类里

使用json和mongo进行果壳网异步数据的爬取【python】

Veröffentlicht am 2016-09-16

说明原文连接【点我】

1、在原文基础上稍作修改,增加了mysql数据库的代码,但是在数据库中的显示结果不理想,主要是其格式不确定怎么设置。

2、本文亮点使用json分析了异步数据,用的方法比较麻烦,但是起作用,具体为通过firefox的网络+XHR功能,鼠标逐渐往下拉,来得到get请求,查看右侧的结果,以及找到步进规律和对应的json网址,如下图:

3、配置:需要安装mongodb,并配置,同时建议安装其图形化工具robomongo,会方便不少,, mongo代码:

#coding:utf-8
from bs4 import BeautifulSoup
import requests
import json
import pymongo

url = 'http://www.guokr.com/scientific/'

def dealData(url):
    client = pymongo.MongoClient('localhost', 27017)
    guoke = client['guoke']
    guokeData = guoke['guokeData']
    web_data = requests.get(url)
    datas = json.loads(web_data.text)
    print(datas.keys())
    for data in datas['result']:
        guokeData.insert_one(data)

def start():
    urls = ['http://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset={}&_=1462252453410'.format(str(i)) for i in range(20, 100, 20)]
    for url in urls:
        dealData(url)

start()

4、输出结果到robomongo,如图:

5、使用mysql数据库,由于不确定输出的result应该用什么格式,我就用了varchar,但是这把一个列表都放到varchar中,导致长度非常长,看起来也很不爽,仅做记录。代码:

#coding:utf-8
from bs4 import BeautifulSoup
import requests
import json
import pymysql.cursors

url = 'http://www.guokr.com/scientific/'

def dealData(url):
    # client = pymongo.MongoClient('localhost', 27017)
    # guoke = client['guoke']
    # guokeData = guoke['guokeData']

    web_data = requests.get(url)
    datas = json.loads(web_data.text)
    print(datas.keys())
    for data in datas['result']:
        #guokeData.insert_one(data)
        print(data)
        print (type(data))
        connection = pymysql.connect(host='localhost',
                                     user='root',
                                     password='XXXX',
                                     db='guoke',
                                     charset='utf8'
                                     )

        try:
            # 创建会话指针
            with connection.cursor() as cursor:
                # 创建sql语句
                sql = 'insert into `guoke1` (`result`) values(%s)'
                # 执行sql语句
                cursor.execute(sql, (str(data)))

                # 提交
                connection.commit()
        finally:
            connection.close()

def start():
    urls = ['http://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset={}&_=1462252453410'.format(str(i)) for i in range(20, 100, 20)]
    for url in urls:

        dealData(url)

start()

6、mysql数据显示,如下图,比较杂乱:

7、总结:异步加载的网页爬取有所麻烦,后续会使用selenium工具来相对方便的操作, 同时,可以感觉到mongodb有其特色,

爬取瓜子网上海地区二手车的信息【python】

Veröffentlicht am 2016-09-15

说明原文连接【点我】

1、在原文基础上稍作修改,目标地区为上海,更改了网址显示和价格显示部分。并增加了数据库导入,请把密码XXXX修改为你的密码。

2、本文亮点在网址分析处,使用了CSS path,目前在谷歌浏览器下显示为Copy selector ,这和原文的Copy CSS Path是不同的,就本文,这个分析方法完全避开了正则式,从中,也体现了bs4的强大。

3、代码:

# -*- coding: utf-8 -*-
# python 3.5.2

from bs4 import BeautifulSoup
import requests
import pymysql.cursors

def detailOper(url):
    web_data = requests.get(url)
    # soup = BeautifulSoup(web_data.text, 'lxml')
    soup = BeautifulSoup(web_data.text, 'html.parser')

    # body > div.w > div.list > ul > li:nth-child(1) > div > p.infoBox > a
    # above is the css path , or copy selector in Google Chrome F12
    # we can delete "body > div.w >" as the whole site under Class = 'w'
    # modify it for all cars info: div.list > ul > li > div > p.infoBox > a
    titles = soup.select('div.list > ul > li > div > p.infoBox > a')

    # get price info with F12: body > div.w > div.list > ul > li:nth-child(1) > div > p.priType-s > span > i
    # modify it for all price: div.list > ul > li > div > p.priType-s > span > i
    prices = soup.select('div.list > ul > li > div > p.priType-s > span > i')
    for title, price in zip(titles, prices):
        data = {
        '车型': title.get_text(),
        '网址': 'http://www.guazi.com'+ title.get('href'),
        #'price':price.get_text().replace(u'万', '').replace(' ', '')
        '价格': price.get_text().replace('\n', '').replace(' ', '')
    }

        connection = pymysql.connect(host='localhost',
                                     user='root',
                                     password='XXXX',
                                     db='guazi',
                                     charset='utf8'
                                     )

        try:
            # 创建会话指针
            with connection.cursor() as cursor:
                # 创建sql语句
                sql = 'insert into `guazi1` (`车型`, `价格`, `网址`) values(%s, %s, %s)'
                # 执行sql语句
                cursor.execute(sql, (data['车型'], data['价格'],data['网址']))

                # 提交
                connection.commit()

        finally:
            connection.close()
    # print(data)

def start():
    urls = ['http://www.guazi.com/sh/buy/o{}/'.format(str(i)) for i in range(1, 51, 1)]
    for url in urls:
        detailOper(url)

if __name__ == '__main__':
    start()

4、部分结果展示:

{'车型': '东南V5菱致 2013款 1.5 手动 舒适型CNG', '价格': '已降价', '网址': 'http://www.guazi.com/sh/3000216790x.htm'}
{'车型': '福特蒙迪欧 2013款 致胜 2.3 自动 时尚型', '价格': '9.00万', '网址': 'http://www.guazi.com/sh/3000237200x.htm'}
{'车型': '斯柯达明锐 2010款 明锐 1.6 手动 逸致版', '价格': '3.80万', '网址': 'http://www.guazi.com/sh/3000222224x.htm'}
{'车型': '大众速腾 2014款 速腾 1.4TSI 手动 豪华型', '价格': '已降价', '网址': 'http://www.guazi.com/sh/3000415677x.htm'}
{'车型': '福特蒙迪欧 2011款 蒙迪欧致胜 2.3 自动 时尚型', '价格': '3.99万', '网址': 'http://www.guazi.com/sh/3000218992x.htm'}
{'车型': '大众CC2015款 CC 1.8TSI 双离合 豪华型', '价格': '已降价', '网址': 'http://www.guazi.com/sh/3000431976x.htm'}
{'车型': '大众Polo2014款 1.6 自动 舒适版', '价格': '19.50万', '网址': 'http://www.guazi.com/sh/3000428176x.htm'}
{'车型': '吉利GX7 2013款 1.8 手动 尊贵型', '价格': '已降价', '网址': 'http://www.guazi.com/sh/3000215362x.htm'}
{'车型': '标致3008 2013款 1.6THP 自动 至尚版', '价格': '8.10万', '网址': 'http://www.guazi.com/sh/3000240867x.htm'}
{'车型': '比亚迪F3 2010款 1.5 手动 新白金版 GLX-i 豪华型', '价格': '4.50万', '网址': 'http://www.guazi.com/sh/3000205737x.htm'}
{'车型': '五菱荣光S 2014款 1.2 手动 标准型7-8座', '价格': '9.98万', '网址': 'http://www.guazi.com/sh/3000243019x.htm'}

5、导入到了mysql中,看起来更方便。如果需要对数据进一步操作,可以在数据库中进行相关排序,如下图:

6、本文可拓展点: 有的价格抓取是 已降价,但不知道降价后的价格, 只抓了上海地区的,如果是想全国地区的,研究了网页代码,css path都是body > div.header > div.hd-top.clearfix > div.c2city > a > span 里面没有具体的城市名字,也许是用ajax的? 以后会了再更新。

win10中python3.5.2遇到lxml安装问题缺少vcvarsall.bat的解决方案和记录【python】

Veröffentlicht am 2016-09-15

说明:win10中python3.5.2遇到lxml安装问题的记录

1、错误提示: error: Unable to find vcvarsall.bat

2、由于在python 2.7 和win7下遇到过类似的问题,当时用安装wheel文件的方法,不过这次失败, 另外在python2.7时代,是有一个微软的支持版本的: Microsoft Visual C++ Compiler for Python 2.7,只有2.7。

3、该问题windows环境中,python 的 Setup需要调用一个vcvarsall.bat的文件,该文件需要安装c++编程环境才会有,经查知乎上有人给出了答案,由于python 3.5使用的SDK环境和3.4是不同的,所以需要安装VC++最新版,或者VS2015 添加VC和python相关组件, ,请参考:http://www.zhihu.com/question/26857761 里面的“代代树”的回复。但是第一次安装遇到retry的失败,关闭了相关VS的进程,重新装,貌似就可以安装了,但安装完毕后,问题没有解决,依然存在啊,什么鬼?

4、然后又发现别人推荐了https://anaconda.org/或者https://www.continuum.io/downloads的Anaconda安装解决方式,一看官网支持python最新版,这就好感爆棚了。果断下载安装,不过结果依然失败,有点闹腾。又是什么鬼?
原来,漏看了一句,安装后,还需要通过conda install lxml命令,开始还以为他支持python3.5.2是自带了这些安装包,理解错误,

然后通过λ pip install -U lxml
Requirement already up-to-date: lxml in d:\anaconda3\lib\site-packages

发现是把lxml安装在d:\anaconda3\lib\site-packages
所以我尝试把这个lxml文件夹复制到python安装目录对应的site-packages
然后测试原本在pycharm提示缺少lxml库的,继续运行,跳出了需要的结果界面。这下终于搞定了。

1…345…8
Van

Van

71 Artikel
© 2017 Van
Erstellt mit Hexo
Theme - NexT.Muse