{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# SERP Analysis\n", "This notebook analyzes the search page results for the 1.9K recommended keywords returned by Google Keyword Planner for our eight inputs, \"Black girls\", \"Latina girls\", \"Asian girls\", \"White girls\", \"Black boys\", \"Latino boys\", \"Asian boys\", and \"White Boys\".\n", "\n", "Here we determine the 200 most-shared domains across searches, and hand-label each domain as pornographic by Googling the website and checking if the site self-identifies as \"porn\" in the search listing. We found 132 of these domains to be pornographic and use that list to estimate how many of the search results have majority (<50%) pornographic links." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import glob\n", "import json\n", "from collections import Counter\n", "\n", "import urlexpander\n", "import pandas as pd\n", "from bs4 import BeautifulSoup\n", "from tqdm import tqdm" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# input\n", "fn_serp_pattern = '../data/input/browser/*.html'\n", "\n", "# output\n", "fn_top_sites = '../data/intermediary/websites-from-search.csv'\n", "fn_labelled_sites = '../data/intermediary/websites-we-found-to-be-pornographic.csv'\n", "fn_keywords_labelled = '../data/intermediary/keywords-labelled-as-adult.json'" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1976" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# HTML source code of Google searches for all recommended keywords.\n", "files = glob.glob(fn_serp_pattern)\n", "len(files)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will read each search result into BeautifulSoup and parse out the traditional search listings and their respective web domains." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1976/1976 [00:39<00:00, 49.67it/s]\n" ] } ], "source": [ "link_data = []\n", "for fn in tqdm(files):\n", " soup = BeautifulSoup(open(fn))\n", " serp = soup.find('div', attrs={'id' : 'main'})\n", " links = serp.find_all('a', href=True, \n", " attrs = {'ping' : True})\n", " \n", " for i, link in enumerate(links):\n", " if link.find('div', role='heading', style=False):\n", " kw = fn.split('/')[-1].replace('.html', '').replace('_', ' ')\n", " url = link.get('href')\n", " domain = urlexpander.get_domain(url)\n", "\n", " row = {\n", " 'keyword' : kw,\n", " 'url' : url,\n", " 'domain' : domain\n", " }\n", " link_data.append(row)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame(link_data)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
urldomain
keyword
1 girl 5 black guys1010
18 year old black boys99
18 year old black girl1010
18 year old latina girls1010
2 latino boys77
.........
young nude mexican girls1010
young thai gays88
young thai ladyboy99
youporn black girl1010
zexy asian1010
\n", "

1976 rows × 2 columns

\n", "
" ], "text/plain": [ " url domain\n", "keyword \n", "1 girl 5 black guys 10 10\n", "18 year old black boys 9 9\n", "18 year old black girl 10 10\n", "18 year old latina girls 10 10\n", "2 latino boys 7 7\n", "... ... ...\n", "young nude mexican girls 10 10\n", "young thai gays 8 8\n", "young thai ladyboy 9 9\n", "youporn black girl 10 10\n", "zexy asian 10 10\n", "\n", "[1976 rows x 2 columns]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# sanity check to make sure we have ~10 links.\n", "df.groupby('keyword').count()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "domains = Counter()\n", "for kw, _df in df.groupby('keyword'):\n", " domains.update(_df.domain.unique())" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# get the top 200 most shared domain websites.\n", "sites = pd.DataFrame(domains.most_common(200), columns=['website', 'n_searches_found_on'])\n", "sites.to_csv(fn_top_sites, index=False)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
websiten_searches_found_on
0xvideos.com1625
1pornhub.com1573
2xnxx.com1468
3xhamster.com745
4redtube.com420
.........
195blogspot.com6
196surfgayvideo.com6
197pinterest.nz6
198aliexpress.com6
199xfantazy.com6
\n", "

200 rows × 2 columns

\n", "
" ], "text/plain": [ " website n_searches_found_on\n", "0 xvideos.com 1625\n", "1 pornhub.com 1573\n", "2 xnxx.com 1468\n", "3 xhamster.com 745\n", "4 redtube.com 420\n", ".. ... ...\n", "195 blogspot.com 6\n", "196 surfgayvideo.com 6\n", "197 pinterest.nz 6\n", "198 aliexpress.com 6\n", "199 xfantazy.com 6\n", "\n", "[200 rows x 2 columns]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sites" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We Google the top 200 sites, and check to see if they self-identify as \"porn\" in their search listing." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labelled_sites = pd.read_csv(fn_labelled_sites)\n", "len(labelled_sites)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
websiten_searches_found_onidentifies_as_porn
0xvideos.com1625True
1pornhub.com1573True
2xnxx.com1468True
3xhamster.com745True
4redtube.com420True
............
195blogspot.com6False
196surfgayvideo.com6False
197pinterest.nz6False
198aliexpress.com6False
199xfantazy.com6True
\n", "

200 rows × 3 columns

\n", "
" ], "text/plain": [ " website n_searches_found_on identifies_as_porn\n", "0 xvideos.com 1625 True\n", "1 pornhub.com 1573 True\n", "2 xnxx.com 1468 True\n", "3 xhamster.com 745 True\n", "4 redtube.com 420 True\n", ".. ... ... ...\n", "195 blogspot.com 6 False\n", "196 surfgayvideo.com 6 False\n", "197 pinterest.nz 6 False\n", "198 aliexpress.com 6 False\n", "199 xfantazy.com 6 True\n", "\n", "[200 rows x 3 columns]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labelled_sites" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We found 139 out of 200 of the most shared web domains to be pornographic.\n" ] } ], "source": [ "porn_sites = labelled_sites[labelled_sites.identifies_as_porn == True].website.tolist()\n", "\n", "print(f\"We found {len(porn_sites)} out of 200 of the most shared web domains to be pornographic.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our list of sites results in an undercount of pornographic sites, as there is a long tail of domains we do not label." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1137" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.domain.nunique()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we check if recommended keywords’ search results contain majority organic links with references to self-described porn sites. This produces an underestimation." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "kw2is_porn = {}\n", "for kw, _df in df.groupby('keyword'):\n", " matches = _df[_df['domain'].isin(porn_sites)]\n", " if len(matches) / len(_df) > .5:\n", " kw2is_porn[kw] = True\n", " else:\n", " kw2is_porn[kw] = False" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.7839068825910931" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# what percentages of keywords are majority pornographic?\n", "len([k for k,v in kw2is_porn.items() if v]) / len(kw2is_porn)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "with open(fn_keywords_labelled, 'w') as f:\n", " f.write(json.dumps(kw2is_porn))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quick distribution of how many pornographic sites are on search pages:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "kw2ratio = []\n", "for kw, _df in df.groupby('keyword'):\n", " matches = _df[_df['domain'].isin(porn_sites)]\n", " row = {\n", " 'kw' : kw,\n", " 'ratio' : len(matches) / len(_df),\n", " 'count' : len(matches)\n", " }\n", " \n", " kw2ratio.append(row)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "series = pd.cut(pd.DataFrame(kw2ratio).ratio, bins=10)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/leon/miniconda3/lib/python3.7/site-packages/ipykernel_launcher.py:1: FutureWarning: `Series.plot()` should not be called with positional arguments, only keyword arguments. The order of positional arguments will change in the future. Use `Series.plot(kind='bar')` instead of `Series.plot('bar',)`.\n", " \"\"\"Entry point for launching an IPython kernel.\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "series.value_counts().sort_index().plot('bar')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 4 }