python初学者之网络爬虫_Python初学者之网络爬虫(二)

到目前为止我新做了如下事情:

对MySql的读写操作进行了封装

编码风格遵从PEP8

爬取沃米优选网(http://video.51wom.com/)的主播信息

爬取一下网(http://www.yixia.com/)的主播信息和视频信息

其中对MySql的封装代码单独放到了文件mysql.py下,做为一个module使用,这个module虽然简单,但已经实现了select,insert,delete等操作,对MySql封装感兴趣的同学可以参考, 但请不要用于生产环境。推荐去使用和阅读数据库类peewee。

接下来将继续讲述我在数据抓取上的开发经历。

2. 爬取的数据源和逻辑

最终目标:收集到各大直播平台的主播信息和历史播放记录,进而对数据进行聚合分析。

当前已完成:对花椒网的数据收集。

沃米优选网(http://video.51wom.com/)是一个网红数据聚合的网站,它收集了各个直播平台(花椒,熊猫,秒拍,斗鱼,映客,一直播,美拍)的热门主播信息。所以我希望能从它这里获取到各个平台的热门主播信息,之后拿着主播id去对应的直播平台去爬取更详细的信息。

3. 爬取沃米优选网的主播列表页

列表页http://video.51wom.com/截图如下:

初看这是一个列表页,并且底部有分页链接,点击分页时触发表单提交

3.1 分析结论和构思程序逻辑

当点击底部分页时,使用chrom开发者工具,看到有XHR请求如下截图:

从截图和一些测试可以分析出:

a) 要请求第二页以后的数据,需要将相应的cookie和csrf数据提交给网站;

b) 提交的方式是POST的”multipart/form-data”;

c) 提交的参数有_csrf, stage-name, platform, industry等;

d) 请求的返回结果是一个表格列表的html代码;

对于cookie容易拿到,但_csrf如何获取呢?

查看页面源码,发现网站在生成列表页时已经将csrf的值写入了表单;同一个csrf值在后续请求中可以多次使用

由以上分析,程序的逻辑应该这样,

a) 先请求主播列表的首页,获取到csrf值和cookie

b) 将csrf和cookie值保存,用于下次请求

c) 请求主播列表的第二页,第三页等

d) 将获取到的表格列表的html代码使用BeautifulSoup进行解析,遍历每个行,行里的每个列

e) 将获取到的数据写入mysql

3.2 python编码获取沃米优选网的主播信息

a) 构造基础类class Website, 之后为每个网站建立一个class,继承Website

有些请求返回的是html代码,类里设置好html解析器;

有些请求返回的是json串,基类里设置好json的解析器;

请求每个网站时,需要设置不同的header,将header放在基类;

对post的Content-Type:multipart/form-data方式进行函数封装;

对post的Content-Type: application/x-www-form-urlencoded方式分别进行函数封装;

这里面尽量把各种不同的请求方式写成函数,而不使用type参数的形式,便于子类清晰的调用;

注意以下代码为了节省篇幅,不是完整代码,也非PEP8代码规范

classWebsite:### 使用requests.session()能够自动处理cookies

session =requests.session()### 设置html解析器

htmlParser =BeautifulSoup### 设置json解析器

jsonParser =json### 设置headers

headers ={'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/'

'54.0.2840.98 Safari/537.36'}### 直接发起get请求

def get(self, url, params=None):if params isNone:

params={}return self.session.get(url, params=params, headers=self.headers)### 发起get请求并返回解析后的html对象

def get_html(self, url, params=None):

r=self.get(url, params)return self.htmlParser(r.text, 'html.parser')### 发起get请求并返回解析后的json对象

def get_json(self, url, params=None):

r=self.get(url, params)returnself.jsonParser.loads(r.text)### 发起post请求,以Content-Type:multipart/form-data方式

defpost_multi_part(self, url, params):

kwargs=dict()for (k, v) inparams.items():

kwargs.setdefault(k, (None, v))

r= self.session.post(url, files=kwargs, headers=self.headers)return self.htmlParser(r.text, "html.parser")

b) 构造class WoMiYouXuan, 封装对网站沃米优选的请求

方法first_kiss()用于第一次请求网站,获取到csrf值由属性self.csrf保存;

first_kiss()另一个作用是获取到cookie,虽然没有显示处理,因为requests.session()帮我们处理了,自动获取自动提交;

注意在一个实例里,只需调用一次first_kiss()即可,之后就可以多次调用其他的页面请求函数了;

csrf和cookie是由关联的,网站会校验,都要提交;

方法parse_actor_list_page()是具体分析主播的列表html代码,这是一个细致活;

方法spider_actors是骨架函数,循环访问每个分页数据并将结果写入mysql;

classWoMiYouXuan(Website):### 发起post请求时需要将csrf发给网站

csrf = ''

def __init__(self):

self.first_kiss()### 首次访问该网站获取到csrf值并保存到self.csrf, 供其他post请求直接使用

deffirst_kiss(self):

url= 'http://video.51wom.com/'html=self.get_html(url)

self.csrf= html.find('meta', {'name': 'csrf-token'}).attrs['content']### 从主播列表页获取主播信息

def parse_actor_list_page(self, page=1):### 构造参数->发起post请求

url = 'http://video.51wom.com/media/' + str(page) + '.html'keys= ('_csrf', 'stage-name', 'platform', 'industry', 'price', 'follower_num', 'follower_area','page', 'is_video_platform', 'sort_by_price', 'type_by_price')

params=dict()for key inkeys:

params.setdefault(key,'')

params['_csrf'] =self.csrf

params['page'] =str(page)

html=self.post_multi_part(url, params)### 解析主播列表

trs = html.find('div', {'id': 'table-list'}).table.findAll('tr')

trs.pop(0)#去除标题行

actor_list =list()for tr intrs:### 后面太多了,有兴趣的同学去看源码吧

### 骨架函数,循环访问每个分页数据并将结果写入mysql

defspider_actors(self):

page= 1tbl_actor=WMYXActor()whileTrue:

ret=self.parse_actor_list_page(page)for actor in ret['items']:

actor['price_dict'] = json.dumps(actor['price_dict'])

tbl_actor.insert(actor, replace=True)if ret['items_count'] * ret['page'] < ret['total']:

page+= 1

else:break

方法parse_actor_list_page()具体分析主播列表的html代码,这是一个细致活;感受一下代码截图

3.3 知识点总结

a) 表单提交的POST方式

通常只提交一些kv数据时,使用application/x-www-form-urlencoded方式;

通常上传文件时,使用multipart/form-data方式,但此种方式也是可以提交kv类数据的,比如上面的获取主播列表数据时就是使用此方式。

b) Python的网络请求库Requests

这个库太好用了!并且能够对cookie自动处理,比如我在基类Website中的使用方式; 并且使用它构造multipart/form-data方式的post请求也很方便,比如方法Website::post_multi_part()

c) Python中使用正则匹配字符串中的整数,如下代码:

avg_watched = tds[6].get_text(strip=True) #平均观看人数

mode = re.compile(r'\d+')

tmp= mode.findall(avg_watched)

d) 使用try, except机制来实现类似php里的isset(),如下代码:

#判断是否有逗号,比如8,189

try:

index= string.index(',')

string= string.replace(',', '')exceptValueError:

string= string

e) 一定要注意python中的’1’和1是不一样的,需要你自己来做字符串和数字的类型转换

4. 爬取秒拍网的主播和视频信息

在沃米优选网拿到了各个直播平台的主播id, 先实现对一下网(http://www.yixia.com/)的抓取,获取对应的主播和视频信息。

一下网的个人主页地址为http://www.yixia.com/u/uid, 这个uid就是主播id, 如下截图:

4.1 分析结论和构思程序逻辑

a) 在主播个人主页能够拿到主播的个人信息,如头像,昵称,粉丝数等,还能拿到主播的视频列表;

b) 视频列表的加载方式是瀑布流方式,意味着走的是ajax接口;

c) 视频列表接口返回的数据是html代码,仍然需要用BeautifulSoup解析;

d) 请求视频列表接口时需要提交suid参数,这个参数值需要用uid在主播个人页获取;

4.2 python编码一下网的主播信息和视频列表

构造class YiXia(Website),

方法parse_user_page()拿着uid去获取主播个人信息;

方法get_video_list()按分页获取视频列表数据

classYiXia(Website):### 访问主播页面,也是视频列表页,从该页面获取到suid和主播个人信息

defparse_user_page(self, uid):print(self.__class__.__name__ + ':parse_user_page, uid=' +uid)

user=dict()

user['uid'] =uid

url= 'http://www.yixia.com/u/' +uid

bs=self.get_html(url)

div= bs.find('div', {'class': 'box1'})

user['nickname'] = div.h1.a.get_text(strip=True) #昵称

stat= div.ol.get_text(strip=True)

stat= re.split('关注\||粉丝', stat)

user['follow'] = stat[0].strip() #关注数

user['followed'] = stat[1].strip() #粉丝数

### ------这里省略很多代码----

returnuser### AJAX请求视频列表

def get_video_list(self, suid, page=1):

url= 'http://www.yixia.com/gu/u'payload={'page': page,'suid': suid,'fen_type': 'channel'}

json_obj= self.get_json(url, params=payload)

msg= json_obj['msg']

msg= BeautifulSoup(msg, 'html.parser')### 解析视频标题

titles =list()

ps= msg.findAll('p')for p inps:

titles.append(p.get_text(strip=True)) #视频标题

### 解析视频赞和评论数

stats =list()

divs= msg.findAll('div', {'class': 'list clearfix'})for div indivs:

tmp= div.ol.get_text(strip=True)

tmp= re.split('赞|\|评论', tmp)

stats.append(tmp)### 解析视频其他数据

videos =list()

divs= msg.findAll('div', {'class': 'D_video'})for (k, div) inenumerate(divs):

video=dict()

video['scid'] = div.attrs['data-scid']### ------这里省略很多代码------

returnvideos### 骨架函数,获取每个视频的每个分页数据

defspider_videos(self, suid, video_count):

page= 1current=0

tbl_video=YiXiaVideo()while current

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值