本文章精选了五个爬虫实例,希望能够给想要入门 Python 爬虫的小伙伴儿们一些帮助。首先来看一个网易精选网站的爬虫例子,可以爬取评价的商品很多,这里选择“iPhone”关键字为例子,因为此类商品种类、样式、颜色等比较多,利于后面的数据分析。进入到网易精选官网,搜索“iPhone”后,先随便点进一个商品。  在商品页面,打开 Chrome 的控制台,切换至 Network 页,再把商品页面切换到评价标签下,选择一个评论文字,如“手机套很薄,裸机的手感”,在 Network 中搜索。 可以发现,评论文字是通过 listByItemByTag.json 传递过来的,点击进入该请求,并拷贝出该请求的 URL: 将该 URL 放入 Postman 中,逐个尝试 url query params,最后能够发现,只需保留 itemId 和 page 两个请求参数即可。 请求返回的是一个 JSON 格式的数据,下面就是分析该 JSON 数据了。不难发现,所有的评论数据都存储在 commentList 中,我们只需保存该数据即可。下面就是如何获取 itemId 的信息了,这个是产品的 ID,我们回到网易精选首页,继续分析。当我们在搜索框中输入关键字进行搜索的时候,同样能够发现在 Network 中有很多请求,此时可以观察各个请求,通过请求文件的名称(此处需要一些经验,守规矩的程序员都不会乱起名字),我们可以定位到搜索时展示搜索结果的请求。 搜索一般都是 search,所以我们就锁定了这个 search.json 的请求。同样把请求 URL 拷贝到 Postman 中,逐个验证传参,最后保留 page 和 keyword 两个参数即可。 该请求返回的数据较多,还是需要耐心的分析数据,也能够发现,在 result->data->directly->searcherResult->result 下面的 id 值,即为我们要获取的产品 ID。以上,我们基本完成了前期的分析工作,下面开始代码的编写。Python def search_keyword(keyword): uri = 'https://you.163.com/xhr/search/search.json' query = { 'keyword': keyword, 'page': 1 } try: res = requests.get(uri, params=query).json() result = res['data']['directly']['searcherResult']['result'] product_id = [] for r in result: product_id.append(r['id']) return product_id except: raise
我这里是获取了 page 为 1 的产品 ID,下面就是通过产品 ID 来获取不同产品下的评论信息。 通过前面的分析,我们可以知道,评论信息都是如下形式的,对这种形式的信息,我们可以很方便地存储进入 MongoDB,然后再慢慢分析数据里的内容。{ 'skuInfo': [ '机型:iphone X', '颜色:透明白' ], 'frontUserName': 'c****x', 'frontUserAvatar': 'https://yanxuan.nosdn./c230f2c2a6e7223810755518ce5cd62f', 'content': '手机套很薄,裸机的手感,硅胶的摸着好舒服,看着屏幕都变大了。颜值很高。', 'createTime': 1554982110981, 'picList': [ 'https://yanxuan.nosdn./749cfcb4877be8e7fce449900d763731.jpg', 'https://yanxuan.nosdn./6744d04efcd7509556b710bc0d9fa6b0.jpg' ], 'commentReplyVO': null, 'memberLevel': 4, 'appendCommentVO': null, 'star': 5, 'itemId': 3444035 } 对于 MongoDB,我们既可以自己搭建,也可以使用网上免费的服务。在这里我介绍一个免费的 MongoDB 服务网站:mlab,使用很简单,就不过多介绍使用过程了。def details(product_id): url = 'https://you.163.com/xhr/comment/listByItemByTag.json' try: C_list = [] for i in range(1, 100): query = { 'itemId': product_id, 'page': i, } res = requests.get(url, params=query).json() if not res['data']['commentList']: break print('爬取第 %s 页评论' % i) commentList = res['data']['commentList'] C_list.append(commentList) time.sleep(1) # save to mongoDB try: mongo_collection.insert_many(commentList) except: continue return C_list except: raise 在这里,details 这个函数还返回了评论的列表,如果你还有其他的逻辑需要对评论处理,可以接收这个函数的返回值,然后处理该列表。最后爬取完成之后,总共是七千多条数据,下面就可以根据个人需要做一些分析了。 完整代码地址:https://github.com/zhouwei713/dataanalysis/tree/master/you163spider。conn = MongoClient('mongodb://%s:%s@ds149974.mlab.com:49974/you163' % ('you163', 'you163')) db = conn.you163 mongo_collection = db.iPhone

Boss 直聘网站爬取 其实分析的步骤都是类似的,无外乎是先分析网站信息,页面组成,然后编写代码爬取数据,最后再保存数据。在 Boss 直聘的官网上搜索 Python,可以看到浏览器的 URL 变为如下: 把该地址复制到 Postman 尝试访问,发现无法得到正确的返回: 此时,再次回到浏览器,查看该请求下面的 headers,可以看到其中有一个 cookie,是很长的一串字符串,我们拷贝这个 cookie 到 Postman 中,再次请求: 成功了,看来 Boss 直聘网也只是做了简单的 cookies 验证。下面就是解析 HTML 数据了,我比较习惯用 BeautifulSoup 这个库来解析。from bs4 import BeautifulSoup import requests
url = 'https://www.zhipin.com/job_detail/?query=python&city=101010100'
res = requests.get(url, headers=header).text print(res) content = BeautifulSoup(res, 'html.parser') ul = content.find_all('ul') print(ul[12]) 可以使用 BeautifulSoup 的 find 函数来查找 HTML 的元素标签,个人觉得还是挺方便的。我们通过分析 HTML 网页可以知道,所有的工作信息都是保存在 ul 这个标签中的,我们可以通过上面的代码拿到页面中所有的 ul 标签,find_all 返回的是一个列表,然后再查看,工作具体位于第几个 ul 中,这样就拿到具体的工作信息了。 如图中所示,我们需要抓取红框中的信息,主要分为四部分。job_details_uri = job.find('h3', attrs={'class': 'name'}).find('a')['href'] job_company = job.find('div', attrs={'class': 'company-text'}).find('h3', attrs={'class': 'name'}).find('a').text job_salary = job.find('h3', attrs={'class': 'name'}).find('span', attrs={'class': 'red'}).text 对于 job 的详情信息,需要用到正则表达式来分割字符串,我们先来看下该部分的原始形式: 又可以把该部分切分成三块,site、year 和 edu。可以使用正则的 group 特性,帮助我们完成切分,最后我写的正则如下:rege = r'<p>([\u4e00-\u9fa5 ]+)<em class='vline'></em>([\d+-年]+|[\u4e00-\u9fa5]+)<em class='vline'></em>([\u4e00-\u9fa5]+)'
正则表达式的具体写法这里就不说了,不熟悉的可以自行查找下。
for job in jobs: job_dict = {} job_details_uri = job.find('h3', attrs={'class': 'name'}).find('a')['href'] job_company = job.find('div', attrs={'class': 'company-text'}).find('h3', attrs={'class': 'name'}).find('a').text job_salary = job.find('h3', attrs={'class': 'name'}).find('span', attrs={'class': 'red'}).text job_details = str(job.find('p')) print(job_details) job_rege = re.match(rege, job_details) job_dict['name'] = job_company job_dict['uri'] = job_details_uri job_dict['salary'] = job_salary job_dict['site'] = job_rege.group(1) job_dict['year'] = job_rege.group(2) job_dict['edu'] = job_rege.group(3) job_list.append(job_dict) print(job_list) 由于我们最后还是得到了一个列表,里面包含字典,同样可以快捷的保存到 MongoDB 中。通过查看 Boss 网站的下一页源码可得到翻页 URL 的规律:https://www.zhipin.com/c101010100/?query=python&page= def jobs(page):
for i in range(1, page + 1): job_list = [] try: print('正在抓取第 %s 页数据' % i) uri = '/c101010100/?query=python&page=%s' % i res = requests.get(config.url + uri, headers=header).text content = BeautifulSoup(res, 'html.parser') ul = content.find_all('ul') jobs = ul[12].find_all('li') ... print(job_list)
# save to mongoDB try: mongo_collection.insert_many(job_list) except: continue time.sleep(1) except: continue 因为我上面的正在表达式并不能匹配所有的情况,所以使用 try...except 来忽略了其他不规则的情况。job 详情抓取完毕之后,开始抓取岗位详情,就是每个 job 的具体要求,毕竟知己知彼,百战不殆。我们可以从 URI 中获得每个工作的详情页面地址,然后再拼接到 Boss 的主 URL 上:https://www.zhipin.com/job_detail/a8920821a7487a901HJ43tm7EFY~.html 再来看下工作详情页面,所有的任职描述都在如下的 div 标签中:没有什么特殊的,直接用 BeautifulSoup 解析即可。job_conn = MongoClient('mongodb://%s:%s@ds151612.mlab.com:51612/boss' % ('boss', 'boss123')) job_db = job_conn.boss job_collection = job_db.boss
details_collection = job_db.job_details
def run_main(): jobs = job_collection.find() for job in jobs: print('获得工作的uri ', job['uri']) get_details(job) time.sleep(1)
def get_details(items): base_url = config.url url = base_url + items['uri'] company_name = items['name'] try: res = requests.get(url, headers=header).text content = BeautifulSoup(res, 'html.parser') text = content.find('div', attrs={'class': 'text'}).text.strip() result = {'name': company_name, 'details': text} details_collection.insert_one(result) except: raise
if __name__ == '__main__': run_main() 注意下这里的 MongoDB 配置,是同一个 db 下的不同 collection。这样,也就完成了直聘网站相关岗位的数据爬取。完整代码地址:https://github.com/zhouwei713/dataanalysis/tree/master/bossspider。job_conn = MongoClient('mongodb://%s:%s@ds151612.mlab.com:51612/boss' % ('boss', 'boss123')) job_db = job_conn.boss job_collection = job_db.boss details_collection = job_db.job_details
这里的微博爬虫,我主要实现的是输入你关心的某个大 V 的微博名称,以及某条微博的相关内容片段,即可自动爬取相关该大 V 一段时间内发布的微博信息和对应微博的评论信息。与上面的 Boss 直聘网站类似,爬取微博也需要获取响应的 cookie。 用浏览器打开微博页面,拷贝出对应的 Cookie,保存到本地。既然是某位大 V,这里就肯定涉及到了搜索的事情,我们可以先来尝试下微博自带的搜索,地址如下:同样是先放到 Postman 里请求下,看看能不能直接访问: 是可以的,这就省去了我们很多的麻烦。下面就是来分析并解析响应消息,拿到对我们有用的数据。经过观察可知,这个接口返回的数据中,有一个 UID 信息,是每个微博用户的唯一 ID,我们可以拿过来留作后面使用。 至于要如何定位到这个 UID,我也已经在图中做了标注,相信你只要简单分析下就能明白。def get_uid(name): try: url = 'https://s.weibo.com/user?q=%s' % name res = requests.get(url).text content = BeautifulSoup(res, 'html.parser') user = content.find('div', attrs={'class': 'card card-user-b s-pg16 s-brt1'}) user_info = user.find('div', attrs={'class': 'info'}).find('div') href_list = user_info.find_all('a') if len(href_list) == 3: title = href_list[1].get('title') if title == '微博个人认证': uid = href_list[2].get('uid') return uid elif title == '微博会员': uid = href_list[2].get('uid') return uid else: print('There are something wrong') return False except: raise 还是通过 BeautifulSoup 来定位获取元素,最后返回 UID 信息。M 站一般是指手机网页端的页面,也就是为了适配 mobile 移动端而制作的页面。一般的网站都是在原网址前面加“m.”来作为自己 M 站的地址,比如:m.baidu.com 就是百度的 M 站。我们来打开微博的 M 站,再进入到林志玲的微博页面看看 Network 中的请求,有没有什么惊喜呢?https://m.weibo.cn/api/container/getIndex?uid=1312412824&luicode=10000011&lfid=100103type%3D1%26q%3D%E6%9E%97%E5%BF%97%E7%8E%B2&containerid=1005051312412824 接着继续拖动网页,发现 Network 中又有类似的 URL:
https://m.weibo.cn/api/container/getIndex?uid=1312412824&luicode=10000011&lfid=100103type%3D1%26q%3D%E6%9E%97%E5%BF%97%E7%8E%B2&containerid=1076031312412824 URL 类似,但是第一个返回的数据是用户信息,而第二个返回的则是用户的微博信息,显然第二个 URL 是我们需要的。同样道理,把第二个 URL 放到 Postman 中,看看哪些参数是可以省略的。 最后我们发现,只要传入正确的 containerid 信息,就能够返回对应的微博信息,可是 containerid 信息又从哪里来呢?我们刚刚获得了一个 UID 信息,现在来尝试下能不能通过这个 UID 来获取到 containerid 信息。这里就又需要一些经验了,我可以不停的尝试给接口“m.weibo.cn/api/container/getIndex”添加不同的参数,看看它会返回些什么信息,比如常见的参数名称 type、id、value、name 等。最终,在我不懈的努力下,发现 type 和 value 的组合是成功的,可以拿到对应的 containerid 信息。 现在就可以编写代码,获取对应的 containerid 了(如果你细心的话,还可以看到这个接口还返回了很多有意思的信息,可以自己尝试着抓取)。def get_userinfo(uid): try: url = 'https://m.weibo.cn/api/container/getIndex?type=uid&value=%s' % uid res = requests.get(url).json() containerid = res['data']['tabsInfo']['tabs'][1]['containerid'] mblog_counts = res['data']['userInfo']['statuses_count'] followers_count = res['data']['userInfo']['followers_count'] userinfo = { 'containerid': containerid, 'mblog_counts': mblog_counts, 'followers_count': followers_count } return userinfo except: raise 拿到 containerid 信息之后,我们就可以使用上面第二个 URL 来获取微博信息了,这里还是同样的问题——分页。怎么处理分页呢,继续改造这个 getIndex 接口,继续尝试传递不同的参数给它。这次给它传递 containerid 和 page 信息,就可以完成分页请求了。 传递的 page 为 3 时,其实是获取当前新浪微博的第 4 页数据,后面我们就可以用这个 URL 来获取微博信息了。该接口返回的是 JSON 数据,解析起来就比较方便了。微博信息就保存在 res['data']['cards'] 下面,有评论、转发、点赞数量等信息。于是我们解析该 JSON 数据的函数就有了:def get_blog_info(cards, i, name, page): blog_dict = {} if cards[i]['card_type'] == 9: scheme = cards[i]['scheme'] # 微博地址 mblog = cards[i]['mblog'] mblog_text = mblog['text'] create_time = mblog['created_at'] mblog_id = mblog['id'] reposts_count = mblog['reposts_count'] # 转发数量 comments_count = mblog['comments_count'] # 评论数量 attitudes_count = mblog['attitudes_count'] # 点赞数量 with open(name, 'a', encoding='utf-8') as f: f.write('----第' + str(page) + '页,第' + str(i + 1) + '条微博----' + '\n') f.write('微博地址:' + str(scheme) + '\n' + '发布时间:' + str(create_time) + '\n' + '微博内容:' + mblog_text + '\n' + '点赞数:' + str(attitudes_count) + '\n' + '评论数:' + str(comments_count) + '\n' + '转发数:' + str(reposts_count) + '\n') blog_dict['mblog_id'] = mblog_id blog_dict['mblog_text'] = mblog_text blog_dict['create_time'] = create_time return blog_dict else: print('没有任何微博哦') return False 我们还要实现通过微博的一些字段,来定位到某个微博,从而抓取该微博下的评论的功能。再定义一个函数,调用上面的 get_blog_info 函数,从其返回的字典中拿到对应的微博信息,再和需要比对的我们输入的微博字段做比较,如果包含,那么就说明找到我们要的微博啦。def get_blog_by_text(containerid, blog_text, name): blog_list = [] page = 1 while True: try: url = 'https://m.weibo.cn/api/container/getIndex?containerid=%s&page=%s' % (containerid, page) res_code = requests.get(url).status_code if res_code == 418: print('访问太频繁,过会再试试吧') return False res = requests.get(url).json() cards = res['data']['cards'] if len(cards) > 0: for i in range(len(cards)): print('-----正在爬取第' + str(page) + '页,第' + str(i+1) + '条微博------') blog_dict = get_blog_info(cards, i, name, page) blog_list.append(blog_dict) if blog_list is False: break mblog_text = blog_dict['mblog_text'] create_time = blog_dict['create_time'] if blog_text in mblog_text: print('找到相关微博') return blog_dict['mblog_id'] elif checkTime(create_time, config.day) is False: print('没有找到相关微博') return blog_list page += 1 time.sleep(config.sleep_time) else: print('没有任何微博哦') break
except: pass 这里调用了一个工具函数 checkTime 和一个配置文件 config。def checkTime(inputtime, day): try: intime = datetime.datetime.strptime('2019-' + inputtime, '%Y-%m-%d') except: return '时间转换失败'
now = datetime.datetime.now() n_days = now - intime days = n_days.days if days < day: return True else: return False 定义这个函数的目的是为了限制搜索时间,比如对于 90 天以前的微博,就不再搜索了,也是提高效率。而 config 配置文件里,则定义了一个配置项 day,来控制可以搜索的时间范围:day = 90 # 最久抓取的微博时间,60即为只抓取两个月前到现在的微博 sleep_time = 5 # 延迟时间,建议配置5-10s
https://weibo.com/1312412824/HxFY84Gqb?filter=hot&root_comment_id=0&type=comment#_rnd1567155548217 
https://weibo.com/aj/v6/comment/big?ajwvr=6&id=4380261561116383&from=singleWeiBo&__rnd=1567155729639 同样使用 Postman 进行 URL 精简和分页处理,可以得到最后的 URL 为:
https://weibo.com/aj/v6/comment/big?ajwvr=6&id=%s&page=%s def get_comment(self, mblog_id, page): comment = [] for i in range(0, page): print('-----正在爬取第' + str(i) + '页评论') url = 'https://weibo.com/aj/v6/comment/big?ajwvr=6&id=%s&page=%s' % (mblog_id, i) req = requests.get(url, headers=self.headers).text html = json.loads(req)['data']['html'] content = BeautifulSoup(html, 'html.parser') comment_text = content.find_all('div', attrs={'class': 'WB_text'}) for c in comment_text: _text = c.text.split(':')[1] comment.append(_text) time.sleep(config.sleep_time)
return comment
def download_comment(self, comment): comment_pd = pd.DataFrame(columns=['comment'], data=comment) timestamp = str(int(time.time())) comment_pd.to_csv(timestamp + 'comment.csv', encoding='utf-8') 最后,我们开始定义运行函数,把需要用户输入的相关信息都从运行函数中获取并传递给后面的逻辑函数中。from weibo_spider import WeiBo from config import headers
def main(name, spider_type, text, page, iscomment, comment_page): print('开始...') weibo = WeiBo(name, headers) ...
if __name__ == '__main__': target_name = input('type the name: ') spider_type = input('type spider type(Text or Page): ') text = '你好' page_count = 10 iscomment = 'No' comment_page_count = 100 while spider_type not in ('Text', 'text', 'Page', 'page'): spider_type = input('type spider type(Text or Page): ') ... 通过 input 函数接受用户输入信息,再判断程序执行。class WeiBo(object):
def __init__(self, name, headers): self.name = name self.headers = headers
def get_uid(self): # 获取用户的 UID ...
def get_userinfo(self, uid): # 获取用户信息,包括 containerid ...
def get_blog_by_page(self, containerid, page, name): # 获取 page 页的微博信息 ...
def get_blog_by_text(self, containerid, blog_text, name): # 一个简单的搜索功能,根据输入的内容查找对应的微博 ...
def get_comment(self, mblog_id, page): # 与上个函数配合使用,用于获取某个微博的评论 ...
def download_comment(self, comment): # 下载评论 ... 在类的初始化函数中,传入需要爬取的大 V 名称和我们准备好的 headers(cookie),然后把上面写好的函数写道该类下,后面该类的实例 weibo 就能够调用这些函数了。import datetime from config import day
def checkTime(inputtime, day): ...
def get_blog_info(cards, i, name, page): ...
 完整代码地址:https://github.com/zhouwei713/weibo_spider。不过这里有一个问题,以前的懂球帝是带有搜索功能的,所以我们能从搜索功能中找到一个用于搜索的 API,但是现在该功能不见了,所以这里已经没有办法展示如何拿到搜索 API 的过程了。http://api.dongqiudi.com/search?keywords=&type=all&page= 我们可以通过给 keyword 传入“女神大会”关键字,来获取到女神大会相关的信息:
id 是对应的每个网页的 id; thumb 是女神的封面图片; url 对应的也是女神所在页面的地址信息。 于是,我们可以通过输入不同的 page 数值,获取到所有的 JSON 信息,并解析 JSON,保存我们需要的数据:def get_list(page): nvshen_id_list = [] nvshen_id_picture = [] for i in range(1, page): print('获取第' + str(i) + '页数据') url = 'http://api.dongqiudi.com/search?keywords=%E5%A5%B3%E7%A5%9E%E5%A4%A7%E4%BC%9A&type=all&page=' + str(i) html = requests.get(url=url).text news = json.loads(html)['news'] if len(news) == 0: print('没有更多啦') break nvshen_id = [k['id'] for k in news] nvshen_id_list = nvshen_id_list + nvshen_id nvshen_id_picture = nvshen_id_picture + [{k['id']: k['thumb']} for k in news] time.sleep(1) return nvshen_id_list, nvshen_id_picture 我们把上面 API 拿到的 url 字段放到懂球帝的主地址下,拼接成如下 url:http://www.dongqiudi.com/news/1193890  我们观察该页面,发现球迷朋友们的评分都是展示在页面上的,且是上一期女神的评分,于是我决定把所有的 HTML 下载到本地,然后再慢慢解析页面,抽取数据:def download_page(nvshen_id_list): for i in nvshen_id_list: print('正在下载ID为' + i + '的HTML网页') url = 'https://www.dongqiudi.com/news/%s' % i download = DownloadPage() html = download.getHtml(url) download.saveHtml(i, html) time.sleep(2)
class DownloadPage(object): def getHtml(self, url): html = requests.get(url=url, cookies=config.session, headers=config.header).content return html
def saveHtml(self, file_name, file_content): with open('html_page/' + file_name + '.html', 'wb') as f: f.write(file_content) download_page 函数接收一个列表(就是上一个函数的返回值 nvshen_id_list),通过 requests 库来请求页面并保存至本地。同时为了方式请求过于频繁,做了 2 秒的延时等待设置。这里还要注意一点的是,这里是设置了 cookies 和 headers 的,否则是无法拿到正常 HTML 数据的,headers 还是从浏览器中手动拷贝出来:session = { 'dqduid': 'yours'} header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win32; x32; rv:54.0) Gecko/20100101 Firefox/54.0', 'Connection': 'keep-alive'} 对于 HTML 的解析,我依旧使用 BeautifulSoup。主要需要获取 score 信息,但是由于好多 HTML 页面写的都不是很规则,故而这里耗费了比较多的时间。
content.find_all('span', attrs={'style': 'color:#ff0000'})
但是有些页面的规则不同,所以会存在无法解析一部分 HTML 文件,对于无法处理的文件,由于也不多,就手工处理了。 当然,感觉这里使用正则应该会好很多。代码过长,为了不影响阅读,就不贴出来了,可以到 GitHub 上查看完整代码。def deal_loaclfile(nvshen_id_picture): files = os.listdir('html_page/') nvshen_list = [] special_page = [] for f in files: ... return nvshen_list, special_page
def get_picture(c, t_list, n_id_p): nvshen_l = [] tmp_prev_id = c.find_all('a', attrs={'target': '_self'}) for j in tmp_prev_id: ... 有一部分 HTML 代码不是很规范,专门提出了这一部分: w_list = ['吴宣仪', '30万', '826965', '68', '825847', 'https://img1.dongqiudi.com/fastdfs3/M00/74/54/180x135/crop/-/ChOxM1vIPpOAZT8AAAHza_WMyRk175.png'] g_list = ['关之琳', '20万', '813611', '88', '812559', 'https://img1.dongqiudi.com/fastdfs3/M00/6B/94/180x135/crop/-/ChOxM1u1gx2AZ7qmAABi3gRdHS8715.jpg'] t_list = ['佟丽娅', '22万', '797779', '93', '795697', 'https://img1.dongqiudi.com/fastdfs3/M00/60/A7/180x135/crop/-/ChOxM1ufUh2AJdR0AABXtcU22fg956.jpg'] y_list = ['杨丞琳', '7万', '1173681', '45', '1168209', 'https://img1./fastdfs4/M00/CA/F7/ChMf8F0pTOKAaefqAA5nOMM0LK0171.jpg'] 对于数据的保存,直接保存在了本地的 CSV 中,代码就不贴了。完整代码地址:https://github.com/zhouwei713/data_analysis/tree/master/nvshendahui。最后,我们再来看看豆瓣的爬取。其实豆瓣网站还是蛮友好的,没有什么反爬机制,所以我们也需要投桃报李,注意爬虫的速率,不要访问过快。在豆瓣电影中搜索“王祖贤”,进入王祖贤主页后,点击全部影人图片,进入到影人图片页面。在该页面点击下一页,可以看到浏览器的 URL 变化如下:https://movie.douban.com/celebrity/1166896/photos/?type=C&start=30&sortby=like&size=a&subtype=a 继续使用 Postman 来分析 URL,可以很轻松的得知,start 就是类似于 page 的页数控制参数,而且步长为 30,即第一页是 start = 0,第二页为 start = 30,第三页为 start = 60,以此类推。
a 标签中的链接可以得到每张图片的评论信息; img 标签中的链接可以用来保存女神的海报。
def get_posters(): comment_url_list = [] picture_list = [] for i in range(0, 40000, 30): url = 'https://movie.douban.com/celebrity/1166896/photos/?type=C&start=%s&sortby=like&size=a&subtype=a' % str(i) req = requests.get(url).text content = BeautifulSoup(req, 'html.parser') chekc_point = content.find('span', attrs={'class': 'next'}).find('a') if chekc_point != None: data = content.find_all('div', attrs={'class': 'cover'}) for k in data: ulist = k.find('a')['href'] plist = k.find('img')['src'] comment_url_list.append(ulist) picture_list.append(plist) else: break return comment_url_list, picture_list
之后,就可以下载海报了。 然后我们手动跳转到每周海报的详情页面,继续查看评论信息。 通过 BeautifulSoup 可以很容易地获得评论信息,然后保存到 MongoDB 中。def get_comment(comment_l): client = pymongo.MongoClient('mongodb://douban:douban1989@ds149744.mlab.com:49744/douban') db = client.douban mongo_collection = db.comment comment_list = [] comment = [] print('Save to MongoDB') for i in comment_l: response = requests.get(i).text content = BeautifulSoup(response, 'html.parser') tmp_list = content.find_all('div', attrs={'class': 'comment-item'}) comment_list = comment_list + tmp_list for k in comment_list: tmp_comment = k.find('p').text mongo_collection.insert_one({'comment': tmp_comment}) comment.append(tmp_comment) print('Save Finish!') 完整代码地址:https://github.com/zhouwei713/douban/tree/master/wangzuxian_poster。client = pymongo.MongoClient('mongodb://douban:douban1989@ds149744.mlab.com:49744/douban') db = client.douban mongo_collection = db.comment
本文章分享了五个爬虫的实战例子,由于为了照顾篇幅,不至于过长,所以省去了一些繁琐重复的代码解释。当然,代码部分难免会有些错误、不规范的地方,还请包涵。在文章中,大部分代码都是仅仅给出了一些思路和主要框架,还希望励志于学习爬虫的你,先好好思考爬虫思路,手动自行敲一遍代码,这样才能达到最好的学习效果。作者:周萝卜,Python 爱好者,个人公众号:萝卜大杂烩。
|