当前位置:首页 > Python爬虫 > Python爬虫入门与进阶

Python爬虫入门与进阶

作者:二营长 发布时间:2016-12-11 点击:

爬虫是在没有(用)API获取数据的情况下以Hack的方式获取数据的一种有效手段;进阶,就是从爬取简单页面逐渐过渡到复杂页面的过程。针对特定需求,爬取的网站类型不同,可以使用不同的python库相结合,达到快速抓取数据的目的。但是无论使用什么库,第一步分析目标网页的页面元素发现抓取规律总是必不可少的:有些爬虫是通过访问固定url前缀拼接不同的后缀进行循环抓取,有些是通过一个起始url作为种子url继而获取更多的目标url递归抓取;有些网页是静态数据可以直接获取,有些网页是js渲染数据需要构造二次请求……如果统统都写下来,一篇文章是不够的,这里举几个典型的栗子:

以从OPENISBN网站抓取图书分类信息为例,我有一批图书需要入库,但是图书信息不全,比如缺少图书分类,此时需要去openisbn.com网站根据ISBN号获取图书的分类信息。如《失控》这本书, ISBN: 7513300712 ,对应url为 http://openisbn.com/isbn/7513300712/,分析url规律就是以http://openisbn.com/isbn/作为固定前缀然后拼接ISBN号得到;然后分析页面元素作为固定前缀然后拼接ISBN号得到;然后分析页面元素,Chrome右键 —> 检查:直接使用urllib2 + re 来获得“Category:” 信息:

import re
import urllib2
isbn = '7513300712'
url = ' 
category_pattern = re.compile(r'Category: *.*, ')
html = urllib2.urlopen(url).read()
category_info = category_pattern.findall(html)
if len(category_info) > 0 :
    print category_info[0]
else:
    print 'get category failed.'

输出:

Category: 现当代小说, 小说,

2.选择合适的定位元素:

由于页面中只有一行“Category:” 信息,正则表达式提取就行,如果有很多行的话就需要缩小查找范围了,BeautifulSoup库就可以用来定位查找范围。通过分析可知,包含所需“Category:” 最近一层的div 是 <div class=“PostContent”>,仔细观察,外层还有一个 <div class=“PostContent”>,而 <div class=“Post”> 也是一样,这样如果使用它们来定位范围的话,使用find方法返回的tag对象是最先找到的外层div,范围不够小;使用findAll,返回的tag对象列表还需要遍历,综合得出用<div class=“Article”> 作为定位元素,find方法定位返回的范围够小,又不需要对find结果进行遍历。

使用urllib2 + Beautiful Soup 3 + re 再来提取一次 (Beautiful Soup最新版本为4.4,兼容python3和python2,BS4跟BS3在导包方式上有点差别):

import re,urllib2
from bs4 import BeautifulSoup
isbn = '7513300712'
url = 'http://openisbn.com/isbn/{0}/'.format(isbn)
category_pattern = re.compile(r'Category: *.*, ')
html = urllib2.urlopen(url).read()
soup = BeautifulSoup(html)
div_tag = soup.find('div',{'class':'Article'})
category_info = category_pattern.findall(str(div_tag))
if len(category_info) > 0 :
    print category_info[0]
else:
    print 'get category failed.'

输出:

Category: 现当代小说, 小说,

3. 抓取js渲染的内容:

用baidu搜索日历,获取结果页中的节假日日期

像上次一样直接使用urllib打开网页,发现返回的html中并没有期望得到的内容,原因是我通过浏览器所看到的页面内容实际是等js渲染完成后最终展现的,中间还包含了多次的ajax请求,这样使用urllib一次就不能胜任了,此时就可以让selenium上场了(webdriver用的phantomjs,需要提前下载phantomjs放到当前的PATH路径下),由于要查找的标识 <div class=“op-calendar-new-relative”> 包含了多个,所以这次使用的方法是findAll,然后再对返回的结果进行遍历,解析每个tag对象的a属性,如果包含了“休”字标识,那么这一天就是节假日。

import re
import urllib
from selenium import webdriver
from BeautifulSoup import BeautifulSoup


holiday_list = []
url = 'http://www.baidu.com/s?' + urllib.urlencode({'wd': '日历'})
date_pattern = re.compile(r'date="[\d]+[-][\d]+[-][\d]+"')

driver = webdriver.PhantomJS()
driver.get(url)
html = driver.page_source
driver.quit()

soup = BeautifulSoup(html)
td_div_list = soup.findAll('div',{'class':'op-calendar-new-relative'})
for td_tag in td_div_list:
    href_tag = str(td_tag.a)
    if href_tag.find('休') != -1:
        holiday_date_list = date_pattern.findall(href_tag)
        if len(holiday_date_list) &gt; 0:
            holiday_list.append(holiday_date_list[0].split('"')[1])

print holiday_list

输出:

['2016-4-2', '2016-4-3', '2016-4-4', '2016-4-30', '2016-5-1’]

4. 设置代理,抓取google play排行榜

selenium不仅可以很好的模拟浏览器行为,还可以将网页内容截图保存

from selenium import webdriver

url = 'https://play.google.com/store/apps/top?hl=zh_CN'
proxy_setting = ['--proxy=127.0.0.1:10800', '--proxy-type=socks5']
driver = webdriver.PhantomJS(service_args=proxy_setting)
driver.get(url)
driver.maximize_window()
# driver.implicitly_wait(10)

top_group_list = driver.find_elements_by_css_selector('.id-cluster-container.cluster-container.cards-transition-enabled')
driver.get_screenshot_as_file('top.jpg’)
for top_group in top_group_list:
    group_name = top_group.find_element_by_xpath('div/div[@class="cluster-heading"]/h2/a').text
    for item in top_group.find_elements_by_class_name('title'):
        print u'bound: {0} app: {1}'.format(group_name,item.text)

driver.quit()

原文链接:https://www.zhihu.com/question/35461941/answer/99930298

邮箱:techseo.cn@gmail.com,欢迎交流。
上一篇:Python计数去重代码      下一篇:Python采集百度下拉词、相关词